1/* 2 * Copyright 2012-2019 Aerospike, Inc. 3 * 4 * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 * use this file except in compliance with the License. You may obtain a copy of 9 * the License at http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 * License for the specific language governing permissions and limitations under 15 * the License. 16 */ 17package aerospike 18 19// Bit operations. Create bit operations used by client operate command. 20// Offset orientation is left-to-right. Negative offsets are supported. 21// If the offset is negative, the offset starts backwards from end of the bitmap. 22// If an offset is out of bounds, a parameter error will be returned. 23// 24// Nested CDT operations are supported by optional CTX context arguments. Example: 25// bin = [[0b00000001, 0b01000010],[0b01011010]] 26// Resize first bitmap (in a list of bitmaps) to 3 bytes. 27// BitOperation.resize("bin", 3, BitResizeFlags.DEFAULT, CTX.listIndex(0)) 28// bin result = [[0b00000001, 0b01000010, 0b00000000],[0b01011010]] 29// 30const ( 31 _CDT_BITWISE_RESIZE = 0 32 _CDT_BITWISE_INSERT = 1 33 _CDT_BITWISE_REMOVE = 2 34 _CDT_BITWISE_SET = 3 35 _CDT_BITWISE_OR = 4 36 _CDT_BITWISE_XOR = 5 37 _CDT_BITWISE_AND = 6 38 _CDT_BITWISE_NOT = 7 39 _CDT_BITWISE_LSHIFT = 8 40 _CDT_BITWISE_RSHIFT = 9 41 _CDT_BITWISE_ADD = 10 42 _CDT_BITWISE_SUBTRACT = 11 43 _CDT_BITWISE_SET_INT = 12 44 _CDT_BITWISE_GET = 50 45 _CDT_BITWISE_COUNT = 51 46 _CDT_BITWISE_LSCAN = 52 47 _CDT_BITWISE_RSCAN = 53 48 _CDT_BITWISE_GET_INT = 54 49 50 _CDT_BITWISE_INT_FLAGS_SIGNED = 1 51) 52 53// BitResizeOp creates byte "resize" operation. 54// Server resizes byte[] to byteSize according to resizeFlags (See {@link BitResizeFlags}). 55// Server does not return a value. 56// Example: 57// bin = [0b00000001, 0b01000010] 58// byteSize = 4 59// resizeFlags = 0 60// bin result = [0b00000001, 0b01000010, 0b00000000, 0b00000000] 61func BitResizeOp(policy *BitPolicy, binName string, byteSize int, resizeFlags int, ctx ...*CDTContext) *Operation { 62 return &Operation{ 63 opType: _BIT_MODIFY, 64 ctx: ctx, 65 binName: binName, 66 binValue: ListValue{_CDT_BITWISE_RESIZE, IntegerValue(byteSize), IntegerValue(policy.flags), IntegerValue(resizeFlags)}, 67 encoder: newCDTBitwiseEncoder, 68 } 69} 70 71// BitInsertOp creates byte "insert" operation. 72// Server inserts value bytes into byte[] bin at byteOffset. 73// Server does not return a value. 74// Example: 75// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 76// byteOffset = 1 77// value = [0b11111111, 0b11000111] 78// bin result = [0b00000001, 0b11111111, 0b11000111, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 79func BitInsertOp(policy *BitPolicy, binName string, byteOffset int, value []byte, ctx ...*CDTContext) *Operation { 80 // Packer packer = new Packer(); 81 // init(packer, ctx, INSERT, 3) 82 // packer.packInt(byteOffset) 83 // packer.packBytes(value) 84 // packer.packInt(policy.flags) 85 // return newOperation(_BIT_MODIFY, binName, Value.get(packer.toByteArray())) 86 87 return &Operation{ 88 opType: _BIT_MODIFY, 89 ctx: ctx, 90 binName: binName, 91 binValue: ListValue{_CDT_BITWISE_INSERT, IntegerValue(byteOffset), BytesValue(value), IntegerValue(policy.flags)}, 92 encoder: newCDTBitwiseEncoder, 93 } 94} 95 96// BitRemoveOp creates byte "remove" operation. 97// Server removes bytes from byte[] bin at byteOffset for byteSize. 98// Server does not return a value. 99// Example: 100// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 101// byteOffset = 2 102// byteSize = 3 103// bin result = [0b00000001, 0b01000010] 104func BitRemoveOp(policy *BitPolicy, binName string, byteOffset int, byteSize int, ctx ...*CDTContext) *Operation { 105 106 return &Operation{ 107 opType: _BIT_MODIFY, 108 ctx: ctx, 109 binName: binName, 110 binValue: ListValue{_CDT_BITWISE_REMOVE, IntegerValue(byteOffset), IntegerValue(byteSize), IntegerValue(policy.flags)}, 111 encoder: newCDTBitwiseEncoder, 112 } 113} 114 115// BitSetOp creates bit "set" operation. 116// Server sets value on byte[] bin at bitOffset for bitSize. 117// Server does not return a value. 118// Example: 119// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 120// bitOffset = 13 121// bitSize = 3 122// value = [0b11100000] 123// bin result = [0b00000001, 0b01000111, 0b00000011, 0b00000100, 0b00000101] 124func BitSetOp(policy *BitPolicy, binName string, bitOffset int, bitSize int, value []byte, ctx ...*CDTContext) *Operation { 125 return &Operation{ 126 opType: _BIT_MODIFY, 127 ctx: ctx, 128 binName: binName, 129 binValue: ListValue{_CDT_BITWISE_SET, IntegerValue(bitOffset), IntegerValue(bitSize), BytesValue(value), IntegerValue(policy.flags)}, 130 encoder: newCDTBitwiseEncoder, 131 } 132} 133 134// BitOrOp creates bit "or" operation. 135// Server performs bitwise "or" on value and byte[] bin at bitOffset for bitSize. 136// Server does not return a value. 137// Example: 138// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 139// bitOffset = 17 140// bitSize = 6 141// value = [0b10101000] 142// bin result = [0b00000001, 0b01000010, 0b01010111, 0b00000100, 0b00000101] 143func BitOrOp(policy *BitPolicy, binName string, bitOffset int, bitSize int, value []byte, ctx ...*CDTContext) *Operation { 144 return &Operation{ 145 opType: _BIT_MODIFY, 146 ctx: ctx, 147 binName: binName, 148 binValue: ListValue{_CDT_BITWISE_OR, IntegerValue(bitOffset), IntegerValue(bitSize), BytesValue(value), IntegerValue(policy.flags)}, 149 encoder: newCDTBitwiseEncoder, 150 } 151} 152 153// BitXorOp creates bit "exclusive or" operation. 154// Server performs bitwise "xor" on value and byte[] bin at bitOffset for bitSize. 155// Server does not return a value. 156// Example: 157// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 158// bitOffset = 17 159// bitSize = 6 160// value = [0b10101100] 161// bin result = [0b00000001, 0b01000010, 0b01010101, 0b00000100, 0b00000101] 162func BitXorOp(policy *BitPolicy, binName string, bitOffset int, bitSize int, value []byte, ctx ...*CDTContext) *Operation { 163 return &Operation{ 164 opType: _BIT_MODIFY, 165 ctx: ctx, 166 binName: binName, 167 binValue: ListValue{_CDT_BITWISE_XOR, IntegerValue(bitOffset), IntegerValue(bitSize), BytesValue(value), IntegerValue(policy.flags)}, 168 encoder: newCDTBitwiseEncoder, 169 } 170} 171 172// BitAndOp creates bit "and" operation. 173// Server performs bitwise "and" on value and byte[] bin at bitOffset for bitSize. 174// Server does not return a value. 175// Example: 176// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 177// bitOffset = 23 178// bitSize = 9 179// value = [0b00111100, 0b10000000] 180// bin result = [0b00000001, 0b01000010, 0b00000010, 0b00000000, 0b00000101] 181func BitAndOp(policy *BitPolicy, binName string, bitOffset int, bitSize int, value []byte, ctx ...*CDTContext) *Operation { 182 return &Operation{ 183 opType: _BIT_MODIFY, 184 ctx: ctx, 185 binName: binName, 186 binValue: ListValue{_CDT_BITWISE_AND, IntegerValue(bitOffset), IntegerValue(bitSize), BytesValue(value), IntegerValue(policy.flags)}, 187 encoder: newCDTBitwiseEncoder, 188 } 189} 190 191// BitNotOp creates bit "not" operation. 192// Server negates byte[] bin starting at bitOffset for bitSize. 193// Server does not return a value. 194// Example: 195// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 196// bitOffset = 25 197// bitSize = 6 198// bin result = [0b00000001, 0b01000010, 0b00000011, 0b01111010, 0b00000101] 199func BitNotOp(policy *BitPolicy, binName string, bitOffset int, bitSize int, ctx ...*CDTContext) *Operation { 200 return &Operation{ 201 opType: _BIT_MODIFY, 202 ctx: ctx, 203 binName: binName, 204 binValue: ListValue{_CDT_BITWISE_NOT, IntegerValue(bitOffset), IntegerValue(bitSize), IntegerValue(policy.flags)}, 205 encoder: newCDTBitwiseEncoder, 206 } 207} 208 209// BitLShiftOp creates bit "left shift" operation. 210// Server shifts left byte[] bin starting at bitOffset for bitSize. 211// Server does not return a value. 212// Example: 213// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 214// bitOffset = 32 215// bitSize = 8 216// shift = 3 217// bin result = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00101000] 218func BitLShiftOp(policy *BitPolicy, binName string, bitOffset int, bitSize int, shift int, ctx ...*CDTContext) *Operation { 219 return &Operation{ 220 opType: _BIT_MODIFY, 221 ctx: ctx, 222 binName: binName, 223 binValue: ListValue{_CDT_BITWISE_LSHIFT, IntegerValue(bitOffset), IntegerValue(bitSize), IntegerValue(shift), IntegerValue(policy.flags)}, 224 encoder: newCDTBitwiseEncoder, 225 } 226} 227 228// BitRShiftOp creates bit "right shift" operation. 229// Server shifts right byte[] bin starting at bitOffset for bitSize. 230// Server does not return a value. 231// Example: 232// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 233// bitOffset = 0 234// bitSize = 9 235// shift = 1 236// bin result = [0b00000000, 0b11000010, 0b00000011, 0b00000100, 0b00000101] 237func BitRShiftOp(policy *BitPolicy, binName string, bitOffset int, bitSize int, shift int, ctx ...*CDTContext) *Operation { 238 return &Operation{ 239 opType: _BIT_MODIFY, 240 ctx: ctx, 241 binName: binName, 242 binValue: ListValue{_CDT_BITWISE_RSHIFT, IntegerValue(bitOffset), IntegerValue(bitSize), IntegerValue(shift), IntegerValue(policy.flags)}, 243 encoder: newCDTBitwiseEncoder, 244 } 245} 246 247// BitAddOp creates bit "add" operation. 248// Server adds value to byte[] bin starting at bitOffset for bitSize. BitSize must be <= 64. 249// Signed indicates if bits should be treated as a signed number. 250// If add overflows/underflows, {@link BitOverflowAction} is used. 251// Server does not return a value. 252// Example: 253// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 254// bitOffset = 24 255// bitSize = 16 256// value = 128 257// signed = false 258// bin result = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b10000101] 259func BitAddOp( 260 policy *BitPolicy, 261 binName string, 262 bitOffset int, 263 bitSize int, 264 value int64, 265 signed bool, 266 action BitOverflowAction, 267 ctx ...*CDTContext, 268) *Operation { 269 // return createMathOperation(ADD, policy, binName, ctx, bitOffset, bitSize, value, signed, action) 270 271 actionFlags := action 272 if signed { 273 actionFlags |= _CDT_BITWISE_INT_FLAGS_SIGNED 274 } 275 return &Operation{ 276 opType: _BIT_MODIFY, 277 ctx: ctx, 278 binName: binName, 279 binValue: ListValue{_CDT_BITWISE_ADD, IntegerValue(bitOffset), IntegerValue(bitSize), IntegerValue(value), IntegerValue(policy.flags), IntegerValue(actionFlags)}, 280 encoder: newCDTBitwiseEncoder, 281 } 282} 283 284// BitSubtractOp creates bit "subtract" operation. 285// Server subtracts value from byte[] bin starting at bitOffset for bitSize. BitSize must be <= 64. 286// Signed indicates if bits should be treated as a signed number. 287// If add overflows/underflows, {@link BitOverflowAction} is used. 288// Server does not return a value. 289// Example: 290// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 291// bitOffset = 24 292// bitSize = 16 293// value = 128 294// signed = false 295// bin result = [0b00000001, 0b01000010, 0b00000011, 0b0000011, 0b10000101] 296func BitSubtractOp( 297 policy *BitPolicy, 298 binName string, 299 bitOffset int, 300 bitSize int, 301 value int64, 302 signed bool, 303 action BitOverflowAction, 304 ctx ...*CDTContext, 305) *Operation { 306 // return createMathOperation(SUBTRACT, policy, binName, ctx, bitOffset, bitSize, value, signed, action) 307 308 actionFlags := action 309 if signed { 310 actionFlags |= _CDT_BITWISE_INT_FLAGS_SIGNED 311 } 312 return &Operation{ 313 opType: _BIT_MODIFY, 314 ctx: ctx, 315 binName: binName, 316 binValue: ListValue{_CDT_BITWISE_SUBTRACT, IntegerValue(bitOffset), IntegerValue(bitSize), IntegerValue(value), IntegerValue(policy.flags), IntegerValue(actionFlags)}, 317 encoder: newCDTBitwiseEncoder, 318 } 319} 320 321// BitSetIntOp creates bit "setInt" operation. 322// Server sets value to byte[] bin starting at bitOffset for bitSize. Size must be <= 64. 323// Server does not return a value. 324// Example: 325// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 326// bitOffset = 1 327// bitSize = 8 328// value = 127 329// bin result = [0b00111111, 0b11000010, 0b00000011, 0b0000100, 0b00000101] 330func BitSetIntOp(policy *BitPolicy, binName string, bitOffset int, bitSize int, value int64, ctx ...*CDTContext) *Operation { 331 // Packer packer = new Packer(); 332 // init(packer, ctx, SET_INT, 4) 333 // packer.packInt(bitOffset) 334 // packer.packInt(bitSize) 335 // packer.packLong(value) 336 // packer.packInt(policy.flags) 337 // return newOperation(_BIT_MODIFY, binName, Value.get(packer.toByteArray())) 338 return &Operation{ 339 opType: _BIT_MODIFY, 340 ctx: ctx, 341 binName: binName, 342 binValue: ListValue{_CDT_BITWISE_SET_INT, IntegerValue(bitOffset), IntegerValue(bitSize), IntegerValue(value), IntegerValue(policy.flags)}, 343 encoder: newCDTBitwiseEncoder, 344 } 345} 346 347// BitGetOp creates bit "get" operation. 348// Server returns bits from byte[] bin starting at bitOffset for bitSize. 349// Example: 350// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 351// bitOffset = 9 352// bitSize = 5 353// returns [0b1000000] 354func BitGetOp(binName string, bitOffset int, bitSize int, ctx ...*CDTContext) *Operation { 355 return &Operation{ 356 opType: _BIT_READ, 357 ctx: ctx, 358 binName: binName, 359 binValue: ListValue{_CDT_BITWISE_GET, IntegerValue(bitOffset), IntegerValue(bitSize)}, 360 encoder: newCDTBitwiseEncoder, 361 } 362} 363 364// BitCountOp creates bit "count" operation. 365// Server returns integer count of set bits from byte[] bin starting at bitOffset for bitSize. 366// Example: 367// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 368// bitOffset = 20 369// bitSize = 4 370// returns 2 371func BitCountOp(binName string, bitOffset int, bitSize int, ctx ...*CDTContext) *Operation { 372 return &Operation{ 373 opType: _BIT_READ, 374 ctx: ctx, 375 binName: binName, 376 binValue: ListValue{_CDT_BITWISE_COUNT, IntegerValue(bitOffset), IntegerValue(bitSize)}, 377 encoder: newCDTBitwiseEncoder, 378 } 379} 380 381// BitLScanOp creates bit "left scan" operation. 382// Server returns integer bit offset of the first specified value bit in byte[] bin 383// starting at bitOffset for bitSize. 384// Example: 385// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 386// bitOffset = 24 387// bitSize = 8 388// value = true 389// returns 5 390func BitLScanOp(binName string, bitOffset int, bitSize int, value bool, ctx ...*CDTContext) *Operation { 391 return &Operation{ 392 opType: _BIT_READ, 393 ctx: ctx, 394 binName: binName, 395 binValue: ListValue{_CDT_BITWISE_LSCAN, IntegerValue(bitOffset), IntegerValue(bitSize), _BoolValue(value)}, 396 encoder: newCDTBitwiseEncoder, 397 } 398} 399 400// BitRScanOp creates bit "right scan" operation. 401// Server returns integer bit offset of the last specified value bit in byte[] bin 402// starting at bitOffset for bitSize. 403// Example: 404// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 405// bitOffset = 32 406// bitSize = 8 407// value = true 408// returns 7 409func BitRScanOp(binName string, bitOffset int, bitSize int, value bool, ctx ...*CDTContext) *Operation { 410 return &Operation{ 411 opType: _BIT_READ, 412 ctx: ctx, 413 binName: binName, 414 binValue: ListValue{_CDT_BITWISE_RSCAN, IntegerValue(bitOffset), IntegerValue(bitSize), _BoolValue(value)}, 415 encoder: newCDTBitwiseEncoder, 416 } 417} 418 419// BitGetIntOp creates bit "get integer" operation. 420// Server returns integer from byte[] bin starting at bitOffset for bitSize. 421// Signed indicates if bits should be treated as a signed number. 422// Example: 423// bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101] 424// bitOffset = 8 425// bitSize = 16 426// signed = false 427// returns 16899 428func BitGetIntOp(binName string, bitOffset int, bitSize int, signed bool, ctx ...*CDTContext) *Operation { 429 binValue := ListValue{_CDT_BITWISE_GET_INT, IntegerValue(bitOffset), IntegerValue(bitSize)} 430 if signed { 431 binValue = append(binValue, IntegerValue(_CDT_BITWISE_INT_FLAGS_SIGNED)) 432 } 433 return &Operation{ 434 opType: _BIT_READ, 435 ctx: ctx, 436 binName: binName, 437 binValue: binValue, 438 encoder: newCDTBitwiseEncoder, 439 } 440} 441 442func newCDTBitwiseEncoder(op *Operation, packer BufferEx) (int, error) { 443 params := op.binValue.(ListValue) 444 opType := params[0].(int) 445 if len(op.binValue.(ListValue)) > 1 { 446 return packCDTBitIfcParamsAsArray(packer, int16(opType), op.ctx, params[1:]) 447 } 448 return packCDTBitIfcParamsAsArray(packer, int16(opType), op.ctx, nil) 449} 450 451func packCDTBitIfcParamsAsArray(packer BufferEx, opType int16, ctx []*CDTContext, params ListValue) (int, error) { 452 return packCDTBitIfcVarParamsAsArray(packer, opType, ctx, []interface{}(params)...) 453} 454 455func packCDTBitIfcVarParamsAsArray(packer BufferEx, opType int16, ctx []*CDTContext, params ...interface{}) (int, error) { 456 size := 0 457 n := 0 458 var err error 459 if len(ctx) > 0 { 460 if n, err = packArrayBegin(packer, 3); err != nil { 461 return size + n, err 462 } 463 size += n 464 465 if n, err = packAInt64(packer, 0xff); err != nil { 466 return size + n, err 467 } 468 size += n 469 470 if n, err = packArrayBegin(packer, len(ctx)*2); err != nil { 471 return size + n, err 472 } 473 size += n 474 475 for _, c := range ctx { 476 if n, err = packAInt64(packer, int64(c.id)); err != nil { 477 return size + n, err 478 } 479 size += n 480 481 if n, err = c.value.pack(packer); err != nil { 482 return size + n, err 483 } 484 size += n 485 } 486 } 487 488 if n, err = packArrayBegin(packer, len(params)+1); err != nil { 489 return size + n, err 490 } 491 size += n 492 493 if n, err = packAInt(packer, int(opType)); err != nil { 494 return size + n, err 495 } 496 size += n 497 498 if len(params) > 0 { 499 for i := range params { 500 if n, err = packObject(packer, params[i], false); err != nil { 501 return size + n, err 502 } 503 size += n 504 } 505 } 506 507 return size, nil 508} 509