/**
* Copyright (c) 2011 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include "mongo/base/static_assert.h"
#include "mongo/base/string_data.h"
#include "mongo/db/pipeline/value_internal.h"
#include "mongo/platform/unordered_set.h"
namespace mongo {
class BSONElement;
/** A variant type that can hold any type of data representable in BSON
*
* Small values are stored inline, but some values, such as large strings,
* are heap allocated. It has smart pointer capabilities built-in so it is
* safe and recommended to pass these around and return them by value.
*
* Values are immutable, but can be assigned. This means that once you have
* a Value, you can be assured that none of the data in that Value will
* change. However if you have a non-const Value you replace it with
* operator=. These rules are the same as BSONObj, and similar to
* shared_ptr with stronger guarantees of constness. This is
* also the same as Java's std::string type.
*
* Thread-safety: A single Value instance can be safely shared between
* threads as long as there are no writers while other threads are
* accessing the object. Any number of threads can read from a Value
* concurrently. There are no restrictions on how threads access Value
* instances exclusively owned by them, even if they reference the same
* storage as Value in other threads.
*/
class Value {
public:
/**
* Operator overloads for relops return a DeferredComparison which can subsequently be evaluated
* by a ValueComparator.
*/
struct DeferredComparison {
enum class Type {
kLT,
kLTE,
kEQ,
kGT,
kGTE,
kNE,
};
DeferredComparison(Type type, const Value& lhs, const Value& rhs)
: type(type), lhs(lhs), rhs(rhs) {}
Type type;
const Value& lhs;
const Value& rhs;
};
/** Construct a Value
*
* All types not listed will be rejected rather than converted (see private for why)
*
* Note: Currently these are all explicit conversions.
* I'm not sure if we want implicit or not.
* //TODO decide
*/
Value() : _storage() {} // "Missing" value
explicit Value(bool value) : _storage(Bool, value) {}
explicit Value(int value) : _storage(NumberInt, value) {}
explicit Value(long long value) : _storage(NumberLong, value) {}
explicit Value(double value) : _storage(NumberDouble, value) {}
explicit Value(const Decimal128& value) : _storage(NumberDecimal, value) {}
explicit Value(const Timestamp& value) : _storage(bsonTimestamp, value) {}
explicit Value(const OID& value) : _storage(jstOID, value) {}
explicit Value(StringData value) : _storage(String, value) {}
explicit Value(const std::string& value) : _storage(String, StringData(value)) {}
explicit Value(const Document& doc) : _storage(Object, doc) {}
explicit Value(const BSONObj& obj);
explicit Value(const BSONArray& arr);
explicit Value(const std::vector& vec);
explicit Value(const std::vector& vec);
explicit Value(std::vector vec) : _storage(Array, new RCVector(std::move(vec))) {}
explicit Value(const BSONBinData& bd) : _storage(BinData, bd) {}
explicit Value(const BSONRegEx& re) : _storage(RegEx, re) {}
explicit Value(const BSONCodeWScope& cws) : _storage(CodeWScope, cws) {}
explicit Value(const BSONDBRef& dbref) : _storage(DBRef, dbref) {}
explicit Value(const BSONSymbol& sym) : _storage(Symbol, sym.symbol) {}
explicit Value(const BSONCode& code) : _storage(Code, code.code) {}
explicit Value(const NullLabeler&) : _storage(jstNULL) {} // BSONNull
explicit Value(const UndefinedLabeler&) : _storage(Undefined) {} // BSONUndefined
explicit Value(const MinKeyLabeler&) : _storage(MinKey) {} // MINKEY
explicit Value(const MaxKeyLabeler&) : _storage(MaxKey) {} // MAXKEY
explicit Value(const Date_t& date) : _storage(Date, date.toMillisSinceEpoch()) {}
// TODO: add an unsafe version that can share storage with the BSONElement
/// Deep-convert from BSONElement to Value
explicit Value(const BSONElement& elem);
/** Construct a long or integer-valued Value.
*
* Used when preforming arithmetic operations with int where the
* result may be too large and need to be stored as long. The Value
* will be an int if value fits, otherwise it will be a long.
*/
static Value createIntOrLong(long long value);
/** A "missing" value indicates the lack of a Value.
* This is similar to undefined/null but should not appear in output to BSON.
* Missing Values are returned by Document when accessing non-existent fields.
*/
bool missing() const {
return _storage.type == EOO;
}
/// true if missing() or type is jstNULL or Undefined
bool nullish() const {
return missing() || _storage.type == jstNULL || _storage.type == Undefined;
}
/// true if type represents a number
bool numeric() const {
return _storage.type == NumberDouble || _storage.type == NumberLong ||
_storage.type == NumberInt || _storage.type == NumberDecimal;
}
/**
* Return true if the Value is an array.
*/
bool isArray() const {
return _storage.type == Array;
}
/**
* Returns true if this value is a numeric type that can be represented as a 32-bit integer,
* and false otherwise.
*/
bool integral() const;
/// Get the BSON type of the field.
BSONType getType() const {
return _storage.bsonType();
}
/** Exact type getters.
* Asserts if the requested value type is not exactly correct.
* See coerceTo methods below for a more type-flexible alternative.
*/
Decimal128 getDecimal() const;
double getDouble() const;
std::string getString() const;
Document getDocument() const;
OID getOid() const;
bool getBool() const;
Date_t getDate() const;
Timestamp getTimestamp() const;
const char* getRegex() const;
const char* getRegexFlags() const;
std::string getSymbol() const;
std::string getCode() const;
int getInt() const;
long long getLong() const;
const std::vector& getArray() const {
return _storage.getArray();
}
size_t getArrayLength() const;
/// Access an element of a subarray. Returns Value() if missing or getType() != Array
Value operator[](size_t index) const;
/// Access a field of a subdocument. Returns Value() if missing or getType() != Object
Value operator[](StringData name) const;
/**
* Recursively serializes this value as a field in the object in 'builder' with the field name
* 'fieldName'. This function throws a UserException if the recursion exceeds the server's BSON
* depth limit.
*/
void addToBsonObj(BSONObjBuilder* builder,
StringData fieldName,
size_t recursionLevel = 1) const;
/**
* Recursively serializes this value as an element in the array in 'builder'. This function
* throws a UserException if the recursion exceeds the server's BSON depth limit.
*/
void addToBsonArray(BSONArrayBuilder* builder, size_t recursionLevel = 1) const;
// Support BSONObjBuilder and BSONArrayBuilder "stream" API
friend BSONObjBuilder& operator<<(BSONObjBuilderValueStream& builder, const Value& val);
/** Coerce a value to a bool using BSONElement::trueValue() rules.
*/
bool coerceToBool() const;
/** Coercion operators to extract values with fuzzy type logic.
*
* These currently assert if called on an unconvertible type.
* TODO: decided how to handle unsupported types.
*/
std::string coerceToString() const;
int coerceToInt() const;
long long coerceToLong() const;
double coerceToDouble() const;
Decimal128 coerceToDecimal() const;
Timestamp coerceToTimestamp() const;
Date_t coerceToDate() const;
//
// Comparison API.
//
// Value instances can be compared either using Value::compare() or via operator overloads.
// Most callers should prefer operator overloads. Note that the operator overloads return a
// DeferredComparison, which must be subsequently evaluated by a ValueComparator. See
// value_comparator.h for details.
//
/**
* Compare two Values. Most Values should prefer to use ValueComparator instead. See
* value_comparator.h for details.
*
* Pass a non-null StringData::ComparatorInterface if special string comparison semantics are
* required. If the comparator is null, then a simple binary compare is used for strings. This
* comparator is only used for string *values*; field names are always compared using simple
* binary compare.
*
* @returns an integer less than zero, zero, or an integer greater than
* zero, depending on whether lhs < rhs, lhs == rhs, or lhs > rhs
* Warning: may return values other than -1, 0, or 1
*/
static int compare(const Value& lhs,
const Value& rhs,
const StringData::ComparatorInterface* stringComparator);
friend DeferredComparison operator==(const Value& lhs, const Value& rhs) {
return DeferredComparison(DeferredComparison::Type::kEQ, lhs, rhs);
}
friend DeferredComparison operator!=(const Value& lhs, const Value& rhs) {
return DeferredComparison(DeferredComparison::Type::kNE, lhs, rhs);
}
friend DeferredComparison operator<(const Value& lhs, const Value& rhs) {
return DeferredComparison(DeferredComparison::Type::kLT, lhs, rhs);
}
friend DeferredComparison operator<=(const Value& lhs, const Value& rhs) {
return DeferredComparison(DeferredComparison::Type::kLTE, lhs, rhs);
}
friend DeferredComparison operator>(const Value& lhs, const Value& rhs) {
return DeferredComparison(DeferredComparison::Type::kGT, lhs, rhs);
}
friend DeferredComparison operator>=(const Value& lhs, const Value& rhs) {
return DeferredComparison(DeferredComparison::Type::kGTE, lhs, rhs);
}
/// This is for debugging, logging, etc. See getString() for how to extract a string.
std::string toString() const;
friend std::ostream& operator<<(std::ostream& out, const Value& v);
void swap(Value& rhs) {
_storage.swap(rhs._storage);
}
/** Figure out what the widest of two numeric types is.
*
* Widest can be thought of as "most capable," or "able to hold the
* largest or most precise value." The progression is Int, Long, Double.
*/
static BSONType getWidestNumeric(BSONType lType, BSONType rType);
/// Get the approximate memory size of the value, in bytes. Includes sizeof(Value)
size_t getApproximateSize() const;
/**
* Calculate a hash value.
*
* Meant to be used to create composite hashes suitable for hashed container classes such as
* unordered_map<>.
*
* Most callers should prefer the utilities in ValueComparator for hashing and creating function
* objects for computing the hash. See value_comparator.h.
*/
void hash_combine(size_t& seed, const StringData::ComparatorInterface* stringComparator) const;
/// Call this after memcpying to update ref counts if needed
void memcpyed() const {
_storage.memcpyed();
}
/// members for Sorter
struct SorterDeserializeSettings {}; // unused
void serializeForSorter(BufBuilder& buf) const;
static Value deserializeForSorter(BufReader& buf, const SorterDeserializeSettings&);
int memUsageForSorter() const {
return getApproximateSize();
}
Value getOwned() const {
return *this;
}
private:
/** This is a "honeypot" to prevent unexpected implicit conversions to the accepted argument
* types. bool is especially bad since without this it will accept any pointer.
*
* Template argument name was chosen to make produced error easier to read.
*/
template
explicit Value(const InvalidArgumentType& invalidArgument);
explicit Value(const ValueStorage& storage) : _storage(storage) {}
// does no type checking
StringData getStringData() const; // May contain embedded NUL bytes
ValueStorage _storage;
friend class MutableValue; // gets and sets _storage.genericRCPtr
};
MONGO_STATIC_ASSERT(sizeof(Value) == 16);
inline void swap(mongo::Value& lhs, mongo::Value& rhs) {
lhs.swap(rhs);
}
/**
* This class is identical to Value, but supports implicit creation from any of the types explicitly
* supported by Value.
*/
class ImplicitValue : public Value {
public:
template
ImplicitValue(T arg) : Value(std::move(arg)) {}
/**
* Converts a vector of Implicit values to a single Value object.
*/
static Value convertToValue(const std::vector& vec) {
std::vector values;
for_each(
vec.begin(), vec.end(), ([&](const ImplicitValue& val) { values.push_back(val); }));
return Value(values);
}
};
}
/* ======================= INLINED IMPLEMENTATIONS ========================== */
namespace mongo {
inline size_t Value::getArrayLength() const {
verify(getType() == Array);
return getArray().size();
}
inline StringData Value::getStringData() const {
return _storage.getString();
}
inline std::string Value::getString() const {
verify(getType() == String);
return _storage.getString().toString();
}
inline OID Value::getOid() const {
verify(getType() == jstOID);
return OID(_storage.oid);
}
inline bool Value::getBool() const {
verify(getType() == Bool);
return _storage.boolValue;
}
inline Date_t Value::getDate() const {
verify(getType() == Date);
return Date_t::fromMillisSinceEpoch(_storage.dateValue);
}
inline Timestamp Value::getTimestamp() const {
verify(getType() == bsonTimestamp);
return Timestamp(_storage.timestampValue);
}
inline const char* Value::getRegex() const {
verify(getType() == RegEx);
return _storage.getString().rawData(); // this is known to be NUL terminated
}
inline const char* Value::getRegexFlags() const {
verify(getType() == RegEx);
const char* pattern = _storage.getString().rawData(); // this is known to be NUL terminated
const char* flags = pattern + strlen(pattern) + 1; // first byte after pattern's NUL
dassert(flags + strlen(flags) == pattern + _storage.getString().size());
return flags;
}
inline std::string Value::getSymbol() const {
verify(getType() == Symbol);
return _storage.getString().toString();
}
inline std::string Value::getCode() const {
verify(getType() == Code);
return _storage.getString().toString();
}
inline int Value::getInt() const {
verify(getType() == NumberInt);
return _storage.intValue;
}
inline long long Value::getLong() const {
BSONType type = getType();
if (type == NumberInt)
return _storage.intValue;
verify(type == NumberLong);
return _storage.longValue;
}
};