docs: private ConciseSet performOperation(ConciseSet other, Operator operator)
    {
      // non-empty arguments
      if (this.isEmpty() || other.isEmpty()) {
        return operator.combineEmptySets(this, other);
      }
  
      // if the two operands are disjoint, the operation is faster
      ConciseSet res = operator.combineDisjointSets(this, other);
      if (res != null) {
        return res;
      }
  
      // Allocate a sufficient number of words to contain all possible results.
      // NOTE: since lastWordIndex is the index of the last used word in "words",
      // we require "+2" to have the actual maximum required space.
      // In any case, we do not allocate more than the maximum space required
      // for the uncompressed representation.
      // Another "+1" is required to allows for the addition of the last word
      // before compacting.
      res = empty();
      res.words = new int[1 + Math.min(
          this.lastWordIndex + other.lastWordIndex + 2,
          maxLiteralLengthDivision(Math.max(this.last, other.last)) << (simulateWAH ? 1 : 0)
      )];
  
      // scan "this" and "other"
      WordIterator thisItr = new WordIterator();
      WordIterator otherItr = other.new WordIterator();
      while (true) {
        if (!thisItr.isLiteral) {
          if (!otherItr.isLiteral) {
            int minCount = Math.min(thisItr.count, otherItr.count);
            res.appendFill(minCount, operator.combineLiterals(thisItr.word, otherItr.word));
            //noinspection NonShortCircuitBooleanExpression
            if (!thisItr.prepareNext(minCount) | /* NOT || */ !otherItr.prepareNext(minCount)) {
              break;
            }
          } else {
            res.appendLiteral(operator.combineLiterals(thisItr.toLiteral(), otherItr.word));
            thisItr.word--;
            //noinspection NonShortCircuitBooleanExpression
            if (!thisItr.prepareNext(1) | /* do NOT use "||" */ !otherItr.prepareNext()) {
              break;
            }
          }
        } else if (!otherItr.isLiteral) {
          res.appendLiteral(operator.combineLiterals(thisItr.word, otherItr.toLiteral()));
          otherItr.word--;
          //noinspection NonShortCircuitBooleanExpression
          if (!thisItr.prepareNext() | /* do NOT use  "||" */ !otherItr.prepareNext(1)) {
            break;
          }
        } else {
          res.appendLiteral(operator.combineLiterals(thisItr.word, otherItr.word));
          //noinspection NonShortCircuitBooleanExpression
          if (!thisItr.prepareNext() | /* do NOT use  "||" */ !otherItr.prepareNext()) {
            break;
          }
        }
      }
  
      // invalidate the size
      res.size = -1;
      boolean invalidLast = true;
  
      // if one bit string is greater than the other one, we add the remaining
      // bits depending on the given operation.
      switch (operator) {
        case AND:
          break;
        case OR:
          res.last = Math.max(this.last, other.last);
          invalidLast = thisItr.flush(res);
          invalidLast |= otherItr.flush(res);
          break;
        case XOR:
          if (this.last != other.last) {
            res.last = Math.max(this.last, other.last);
            invalidLast = false;
          }
          invalidLast |= thisItr.flush(res);
          invalidLast |= otherItr.flush(res);
          break;
        case ANDNOT:
          if (this.last > other.last) {
            res.last = this.last;
            invalidLast = false;
          }
          invalidLast |= thisItr.flush(res);
          break;
      }
  
      // remove trailing zeros
      res.trimZeros();
      if (res.isEmpty()) {
        return res;
      }
  
      // compute the greatest element
      if (invalidLast) {
        res.updateLast();
      }
  
      // compact the memory
      res.compact();
  
      return res;
    }