@@ -579,6 +579,80 @@ rocksdb::Status Bitmap::BitOp(engine::Context &ctx, BitOpFlags op_flag, const st
579579 apply_fast_path_op ([](uint64_t &a, uint64_t b) { a |= b; });
580580 } else if (op_flag == kBitOpXor ) {
581581 apply_fast_path_op ([](uint64_t &a, uint64_t b) { a ^= b; });
582+ } else if (op_flag == kBitOpDiff ) {
583+ // X & (~(Y1 | Y2 | ...))
584+ uint64_t others_or[4 ];
585+ while (frag_minlen >= sizeof (uint64_t ) * 4 ) {
586+ for (uint64_t k = 0 ; k < 4 ; k++) {
587+ others_or[k] = 0 ;
588+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
589+ others_or[k] |= lp[i][k];
590+ }
591+ lres[k] = lres[k] & ~others_or[k];
592+ }
593+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
594+ lp[i] += 4 ;
595+ }
596+ lres += 4 ;
597+ j += sizeof (uint64_t ) * 4 ;
598+ frag_minlen -= sizeof (uint64_t ) * 4 ;
599+ }
600+ } else if (op_flag == kBitOpDiff1 ) {
601+ // (~X) & (Y1 | Y2 | ...)
602+ uint64_t others_or[4 ];
603+ while (frag_minlen >= sizeof (uint64_t ) * 4 ) {
604+ for (uint64_t k = 0 ; k < 4 ; k++) {
605+ others_or[k] = 0 ;
606+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
607+ others_or[k] |= lp[i][k];
608+ }
609+ lres[k] = ~lres[k] & others_or[k];
610+ }
611+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
612+ lp[i] += 4 ;
613+ }
614+ lres += 4 ;
615+ j += sizeof (uint64_t ) * 4 ;
616+ frag_minlen -= sizeof (uint64_t ) * 4 ;
617+ }
618+ } else if (op_flag == kBitOpAndOr ) {
619+ // X & (Y1 | Y2 | ...)
620+ uint64_t others_or[4 ];
621+ while (frag_minlen >= sizeof (uint64_t ) * 4 ) {
622+ for (uint64_t k = 0 ; k < 4 ; k++) {
623+ others_or[k] = 0 ;
624+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
625+ others_or[k] |= lp[i][k];
626+ }
627+ lres[k] = lres[k] & others_or[k];
628+ }
629+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
630+ lp[i] += 4 ;
631+ }
632+ lres += 4 ;
633+ j += sizeof (uint64_t ) * 4 ;
634+ frag_minlen -= sizeof (uint64_t ) * 4 ;
635+ }
636+ } else if (op_flag == kBitOpOne ) {
637+ // (X1 ^ X2 ^ ...) & (~(X1 & X2 & ...))
638+ uint64_t all_and[4 ], all_xor[4 ];
639+ while (frag_minlen >= sizeof (uint64_t ) * 4 ) {
640+ for (uint64_t k = 0 ; k < 4 ; k++) {
641+ all_and[k] = lp[0 ][k];
642+ all_xor[k] = lp[0 ][k];
643+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
644+ all_and[k] &= lp[i][k];
645+ all_xor[k] ^= lp[i][k];
646+ }
647+ lres[k] = all_xor[k] & ~all_and[k];
648+ }
649+ for (uint64_t i = 0 ; i < frag_numkeys; i++) {
650+ lp[i] += 4 ;
651+ }
652+ lres += 4 ;
653+ j += sizeof (uint64_t ) * 4 ;
654+ frag_minlen -= sizeof (uint64_t ) * 4 ;
655+ }
582656 } else if (op_flag == kBitOpNot ) {
583657 while (frag_minlen >= sizeof (uint64_t ) * 4 ) {
584658 lres[0 ] = ~lres[0 ];
@@ -597,6 +671,46 @@ rocksdb::Status Bitmap::BitOp(engine::Context &ctx, BitOpFlags op_flag, const st
597671 for (; j < frag_maxlen; j++) {
598672 output = (fragments[0 ].size () <= j) ? 0 : fragments[0 ][j];
599673 if (op_flag == kBitOpNot ) output = ~output;
674+
675+ // For DIFF, DIFF1, ANDOR, and ONE operations, we need special handling
676+ if (op_flag == kBitOpDiff || op_flag == kBitOpDiff1 || op_flag == kBitOpAndOr ) {
677+ // Calculate OR of all keys except the first one
678+ uint8_t others_or = 0 ;
679+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
680+ byte = (fragments[i].size () <= j) ? 0 : fragments[i][j];
681+ others_or |= byte;
682+ }
683+
684+ if (op_flag == kBitOpDiff ) {
685+ // X & (~(Y1 | Y2 | ...))
686+ output = output & ~others_or;
687+ } else if (op_flag == kBitOpDiff1 ) {
688+ // (~X) & (Y1 | Y2 | ...)
689+ output = ~output & others_or;
690+ } else if (op_flag == kBitOpAndOr ) {
691+ // X & (Y1 | Y2 | ...)
692+ output = output & others_or;
693+ }
694+ frag_res[j] = output;
695+ continue ;
696+ }
697+
698+ if (op_flag == kBitOpOne ) {
699+ // Calculate AND and XOR of all keys
700+ uint8_t all_and = (fragments[0 ].size () <= j) ? 0 : fragments[0 ][j];
701+ uint8_t all_xor = all_and;
702+ for (uint64_t i = 1 ; i < frag_numkeys; i++) {
703+ byte = (fragments[i].size () <= j) ? 0 : fragments[i][j];
704+ all_and &= byte;
705+ all_xor ^= byte;
706+ }
707+ // (X1 ^ X2 ^ ...) & (~(X1 & X2 & ...))
708+ output = all_xor & ~all_and;
709+ frag_res[j] = output;
710+ continue ;
711+ }
712+
713+ // Standard operations: AND, OR, XOR, NOT
600714 for (uint64_t i = 1 ; i < frag_numkeys; i++) {
601715 byte = (fragments[i].size () <= j) ? 0 : fragments[i][j];
602716 switch (op_flag) {
@@ -609,6 +723,8 @@ rocksdb::Status Bitmap::BitOp(engine::Context &ctx, BitOpFlags op_flag, const st
609723 case kBitOpXor :
610724 output ^= byte;
611725 break ;
726+ case kBitOpNot :
727+ // NOT operation ignores other keys after the first one
612728 default :
613729 break ;
614730 }
0 commit comments