TEST(BitAnd, 32and32) { const SafeNum val1(static_cast<int>(0xE0F1U)); const SafeNum val2(static_cast<int>(0xDF01U)); const SafeNum expected(static_cast<int>(0xC001U)); const SafeNum result = val1 & val2; ASSERT_EQUALS(mongo::NumberInt, result.type()); ASSERT_TRUE(expected.isIdentical(result)); } TEST(BitAnd, 64and64) { const SafeNum val1(static_cast<long long>(0xE0F1E0F1E0F1ULL)); const SafeNum val2(static_cast<long long>(0xDF01DF01DF01ULL)); const SafeNum expected(static_cast<long long>(0xC001C001C001ULL)); const SafeNum result = val1 & val2; ASSERT_EQUALS(mongo::NumberLong, result.type()); ASSERT_TRUE(expected.isIdentical(result)); } TEST(BitAnd, MixedSize) { const SafeNum val_small(static_cast<int>(0xE0F1U)); const SafeNum val_big(static_cast<long long>(0xDF01U)); const SafeNum expected(static_cast<long long>(0xC001U)); const SafeNum result_s_b = val_small & val_big; const SafeNum result_b_s = val_big & val_small; ASSERT_EQUALS(mongo::NumberLong, result_s_b.type()); ASSERT_TRUE(expected.isIdentical(result_s_b)); ASSERT_EQUALS(mongo::NumberLong, result_b_s.type()); ASSERT_TRUE(expected.isIdentical(result_b_s));
Status ModifierInc::prepare(mutablebson::Element root, const StringData& matchedField, ExecInfo* execInfo) { _preparedState.reset(new PreparedState(root.getDocument())); // If we have a $-positional field, it is time to bind it to an actual field part. if (_posDollar) { if (matchedField.empty()) { return Status(ErrorCodes::BadValue, "matched field not provided"); } _preparedState->boundDollar = matchedField.toString(); _fieldRef.setPart(_posDollar, _preparedState->boundDollar); } // Locate the field name in 'root'. Note that we may not have all the parts in the path // in the doc -- which is fine. Our goal now is merely to reason about whether this mod // apply is a noOp or whether is can be in place. The remaining path, if missing, will // be created during the apply. Status status = pathsupport::findLongestPrefix(_fieldRef, root, &_preparedState->idxFound, &_preparedState->elemFound); // FindLongestPrefix may say the path does not exist at all, which is fine here, or // that the path was not viable or otherwise wrong, in which case, the mod cannot // proceed. if (status.code() == ErrorCodes::NonExistentPath) { _preparedState->elemFound = root.getDocument().end(); } else if (!status.isOK()) { return status; } // We register interest in the field name. The driver needs this info to sort out if // there is any conflict among mods. execInfo->fieldRef[0] = &_fieldRef; // Capture the value we are going to write. At this point, there may not be a value // against which to operate, so the result will be simply _val. _preparedState->newValue = _val; // // in-place and no-op logic // // If the field path is not fully present, then this mod cannot be in place, nor is a // noOp. if (!_preparedState->elemFound.ok() || _preparedState->idxFound < static_cast<int32_t>(_fieldRef.numParts() - 1)) { return Status::OK(); } // If the value being $inc'ed is the same as the one already in the doc, than this is a // noOp. if (!_preparedState->elemFound.isNumeric()) return Status(ErrorCodes::BadValue, "invalid attempt to increment a non-numeric field"); const SafeNum currentValue = _preparedState->elemFound.getValueSafeNum(); // Update newValue w.r.t to the current value of the found element. _preparedState->newValue += currentValue; // If the result of the addition is invalid, we must return an error. if (!_preparedState->newValue.isValid()) return Status(ErrorCodes::BadValue, "Failed to increment current value"); // If the values are identical (same type, same value), then this is a no-op, and // therefore in-place as well. if (_preparedState->newValue.isIdentical(currentValue)) { _preparedState->noOp = execInfo->noOp = true; _preparedState->inPlace = execInfo->inPlace = true; return Status::OK(); } // If the types are the same, this can be done in place. // // TODO: Potentially, cases where $inc results in a mixed type of the same size could // be in-place as well, but we don't currently handle them. if (_preparedState->newValue.type() == currentValue.type()) { _preparedState->inPlace = execInfo->inPlace = true; } return Status::OK(); }