// bdld_datum.h -*-C++-*- #ifndef INCLUDED_BDLD_DATUM #define INCLUDED_BDLD_DATUM #include <bsls_ident.h> BSLS_IDENT("$Id$ $CSID$") //@PURPOSE: Provide a discriminated variant type with a small footprint. // //@CLASSES: // bdld::Datum: POD type representing general-purpose values // bdld::DatumArrayRef: type for const ref to array of datums // bdld::DatumIntMapEntry: type for entry inside int-map of datums // bdld::DatumIntMapRef: type for const ref to int-map of datums // bdld::DatumMapEntry: type for entry inside map of datums // bdld::DatumMapRef: type for const ref to map of datums // bdld::DatumMutableArrayRef: type for mutable ref to array of datums // bdld::DatumMutableMapRef: type for mutable ref to a map of datums // bdld::DatumMutableMapOwningKeysRef: mutable ref to a map owning keys // //@SEE_ALSO: bdld_datumerror, bdld_datumudt, bdld_datumbinaryref, // bdld_manageddatum // //@DESCRIPTION: This component defines a mechanism, 'bdld::Datum', that // provides a space-efficient discriminated union (i.e., a variant) that holds // the value of either a scalar type (e.g., 'int', 'double', 'Date') or an // aggregate (i.e., array or map) of 'Datum' objects. The set of possible // types that a datum may hold is described in the {Supported Types} section. // // The 'Datum' class is implemented as a POD-type, such that instances of the // class are bitwise copyable and have trivial initialization, assignment and // destruction. The 'Datum' class is also (primarily) designed to be compact, // especially on a 32-bit platform. Being a compact POD type, 'Datum' is // ideal for applications creating and copying very large numbers of variant // values (the canonical use-case is for the values in a spreadsheet). // // However, not all representable values can be stored in-line in footprint of // a 'Datum' object itself. Those types may require memory be allocated for // storage. In order to keep the footprint of a 'Datum' object as small as // possible, a 'Datum' object does not hold a reference to an allocator, and so // memory must be explicitly managed by the user of 'Datum'. See // {Memory Management} for more details. // ///Notion of Value ///--------------- // 'Datum' has a notion of value, but is neither a value-semantic type, nor is // it an in-core value-semantic type (see {'bsldoc_glossary'}). A consequence // of the 'Datum' class's space-efficient design is that it does not fall // neatly into any of the standard BDE type-classifications. The 'Datum' // type's notion of value is expressed by its equality-operator -- notice, in // particular, that two 'Datum' objects compare equal if the values they refer // to are the same. However, 'Datum', as a POD, has compiler supplied copy and // assignment operators that do not copy any of the storage a 'Datum' may be // pointing to, and only copy the address to which the 'Datum' is pointing. // // Notice that the differing treatment of references to external data between // the equality comparison and the copy and assignment operations violates a // couple properties required of a value-semantic type, most obviously: "The // value of an object of the type is independent of any modifiable state that // is not owned exclusively by that object." (see {'bsldoc_glossary'}). // ///Special Floating Point Values ///- - - - - - - - - - - - - - - // Floating point data can represent special values, and of particular interest // for 'Datum' are values of NaN and infinity. 'Datum' may internally store // NaN and infinity values in a different way than the IEEE-754 representation, // and this section describes the resulting behavior for NaN and infinity // values. // ///Treatment of NaN (Not-A-Number) ///- - - - - - - - - - - - - - - - // When storing a NaN value in a 'Datum', 'Datum' guarantees only that *a* NaN // value will be represented, but does not guarantee that the particular bit // pattern supplied for a NaN value will be preserved. Note that an IEEE-754 // representation for 'double' allows for signaling and quiet NaN values, as // well as a sign bit, and other bits of NaN payload data. These non-salient // elements of the "value" of the 'double' may not be preserved (and in the // case of signaling NaNs, cannot be preserved on some platforms). // ///Treatment of Infinity ///- - - - - - - - - - - // 'Datum' is provides unique representations for positive and negative // infinity. IEEE-754 double precisions format requires also only those two // infinity values. (Unlike NaN values, these two infinity values have no // non-normative bits in their representations, or signaling/quiet forms.) // ///Immutability ///------------ // 'Datum' objects are generally immutable, meaning the value stored inside a // 'Datum' object cannot be changed *except* through the assignment operation. // A 'Datum' is copy-assignable, so a 'Datum' object can assigned another // 'Datum' object. On assignment, a 'Datum' object is "shallow-copied". // Meaning that the footprint of original 'Datum' object is copied into the // footprint of the destination 'Datum' object, but if the 'Datum' refers to // dynamically allocated memory, only the value of the address is copied (not // the contents of the dynamic allocation). 'Datum' also exposes a 'clone' // method to "deep-copy" 'Datum' objects, so that any externally allocated // memory (except user defined types) is cloned and not shared like // copy-assignment. See also {Deep Copying}. // ///Memory Management ///----------------- // A primary design goal for 'Datum' is space-efficiency, particularly on // 32-bit platforms. In order to minimize the foot-print (i.e., the 'sizeof') // of a 'Datum' object, 'Datum' does not hold a reference to the allocator that // was used to allocate its contents. This component provides static functions // that allocate dynamic data structures referred to by a 'Datum' object (i.e. // the 'Datum::create*' static functions). This memory is said to be // "externally managed" because it not released when a 'Datum' object is // destroyed, instead clients must explicitly call 'Datum::destroy' on a // 'Datum' to release its memory (see {Analogy to Raw Pointers}). The // 'bdld' package provides tools and components that can simplify the process // of managing the memory (see 'bdld_manageddatum', and the various builder // components like 'bdld_datumarraybuilder'). // ///Analogy to Raw Pointers ///- - - - - - - - - - - - // A good way to understand the model for a 'Datum' object's relationship to // its data is by analogy: The relationship between a 'Datum' object and the // memory to which it refers is analogous to that of a raw-pointer and the data // to which it points. Where 'new' and 'delete' are used allocate and free // memory a that a pointer points to, the static class methods 'Datum::create*' // and 'Datum::destroy' are used to allocate and release the memory a 'Datum' // refers to. // // In order to create a 'Datum' object a client calls one of the 'create*' // static methods on the 'Datum' class. In order to release the data a // 'Datum' holds, a client calls 'destroy'. // // Copying, or copy assigning a 'Datum' object to another behaves just like // copying a raw pointer. This copy does not allocate or deallocate data. // That also means assigning to a datum object is not safe if the 'Datum' being // assigned to refers to dynamically allocated memory, and there isn't a (user // controlled) strategy in place to release that memory. // /// Deep Copying ///- - - - - - - // 'Datum' exposes a 'clone' method that "deep-copies" 'Datum' objects, so that // any dynamically or externally referenced memory is cloned and not shared // like it would be when using a copy or copy-assignment operation. The // exception is {User Defined Types} as they are opaque, so 'Datum' has no way // to deep-copy them. // // The purpose of 'clone' is to create an independent copy of the content of // any 'Datum', which also includes 'Datum' values where 'isExternalreference' // returns 'true' (except of course UDTs, as mentioned above). Cloning a // reference to a string results in an owned string, not a reference to a // string, with the cloned 'Datum' object's 'isExternalReference' returning // 'false'. When cloning a map with keys that are references to external // strings the clone will have deep copies of those string keys, it will become // a map with owned keys. This behavior is intentional. The deep-copy // operation ('clone') is designed to ensure that the lifetime of the new clone // does not, in any way, depend on the lifetime of the original 'Datum', or any // data that 'Datum' may have referenced. So (except for UDTs), if a 'Datum' // is cloned, the original 'Datum' can be destroyed without any effect on the // cloned 'Datum'. // ///Creating a Datum that Requires No Allocation /// - - - - - - - - - - - - - - - - - - - - - - // Datum's containing certain types of scalar values do not require any memory // allocation, so their factory functions do *not* take an allocator. These // values are small enough that they can always fit inside of the footprint of // the 'Datum' object itself. //.. // Datum boolean = Datum::createBoolean(true); // Create a boolean datum // Datum integer = Datum::createInteger(7); // Create a integer // Datum real = Datum::createDouble(2.0); // Create a double //.. // ///Creating a Datum that *May* Require Allocation /// - - - - - - - - - - - - - - - - - - - - - - - // Datum objects containing certain types *may* (or *may*-*not*!) require // memory allocation, so their creation functions *require* an allocator: //.. // bslma::Allocator *allocator = bslma::Default::defaultAllocator(); // Datum datetime = Datum::createDatetime(bdlt::Datetime(), allocator); // Datum int64 = Datum::createInteger64(1LL, allocator); //.. // In the example above, 'createDatetime' takes an allocator, but may not // allocate memory. Depending on the value of the 'Datetime', a 'Datum' might // either store the value within the footprint of the 'Datum' (requiring no // allocation) or allocate external storage. The situations in which creation // functions taking an allocator do, and do not, actually allocate memory is // *implementation*-*defined*. // // Clients of 'Datum' should treat any creation function taking an allocator // *as-if* it allocated memory, and eventually call 'Datum::destroy' on the // resulting 'Datum', even though in some instances memory allocation may not // be required. // ///Destroying a 'Datum' Object ///- - - - - - - - - - - - - - // The contents of a 'Datum' object are destroyed using the static method // 'destroy'. For example: //.. // bslma::Allocator *allocator = bslma::Default::defaultAllocator(); // Datum datetime = Datum::createDatetime(bdlt::Datetime(), allocator); // // Datum::destroy(datetime, allocator); // // 'datetime' now refers to deallocated memory. It cannot be used // // used unless it is assigned a new value. //.. // Notice that the destroyed 'Datum' again behaves similar to a raw-pointer // that has been deallocated: the destroyed 'Datum' refers to garbage and must // be assigned a new value before it can be used. // // For aggregate types -- i.e., maps and arrays -- 'destroy' will recursively // call 'destroy' on the 'Datum' objects that compose the aggregate. The // exception to this is references to external arrays (discussed below). // // The 'destroy' method does not nothing for {User Defined Types} as they are // opaque, unknown, for 'Datum'. // ///References to External Strings and Arrays ///- - - - - - - - - - - - - - - - - - - - - // Although a 'Datum' does not own memory in the traditional sense, a call to // 'Datum::destroy' will release the memory to which that 'Datum' refers. // However, a 'Datum' object also allows a user to create a 'Datum' referring // to an externally managed array or string. For a 'Datum' having a reference // to an external string or array, the 'isExternalReference' method will return // 'true' and 'Datum::destroy' will not deallocate memory for the data; // otherwise, 'isExternalReference' will return 'false' and 'Datum::destroy' // will deallocate memory for the data. // // For example, to create a 'Datum' for an externally managed string: //.. // Datum externalStringRef = Datum::createStringRef("text", allocator); //.. // Notice that the supplied 'allocator' is *not* used to allocate memory in // order copy the contents of the string, but *may* (or *may*-*not*) be used to // allocate meta-data that the 'Datum' stores about the string (e.g., the // string's length). // // To create a 'Datum' that is responsible for the memory of a string: //.. // Datum managedString = Datum::copyString("text", allocator); //.. // Here the contents of the string are copied and managed by the created // datum, and later released by 'Datum::destroy'. // // External references to arrays and strings are important for efficiently // handling memory allocations in situations where a string or array is // externally supplied (e.g., as input to a function) and will clearly outlive // the 'Datum' object being created (e.g., a 'Datum' variable within the scope // of that function). // // In general factory methods of the form 'create*Ref' create a reference to // external data that the 'Datum' is not responsible for, while 'copy*' // methods copy the data and the resulting 'Datum' is responsible for the // allocated memory. // ///Supported Types ///--------------- // The table below describes the set of types that a 'Datum' may be. // //.. // external requires // dataType reference allocation Description // -------- --------- ---------- ----------- // e_NIL no no null value // e_INTEGER no no integer value // e_DOUBLE no no double value // e_STRING maybe maybe string value // e_BOOLEAN no no boolean value // e_ERROR no maybe error value // e_DATE no no date value // e_TIME no no time value // e_DATETIME no maybe date+time value // e_DATETIME_INTERVAL no maybe date+time interval value // e_INTEGER64 no maybe 64-bit integer value // e_USERDEFINED always maybe pointer to a user-defined obj // e_BINARY no maybe binary data // e_DECIMAL64 no maybe Decimal64 // // external requires // dataType reference allocation Description // -------- --------- ---------- ----------- // e_ARRAY maybe maybe array // e_MAP no maybe map keyed by string values // e_INT_MAP no maybe map keyed by 32-bit int values //.. //: o *dataType* - the value returned by the 'type()' //: //: o *external-reference* - whether 'isExternalReference' will return 'true', //: in which case 'Datum::destroy' will not release the externally //: referenced data (see 'References to External Strings and Arrays'}) //: //: o *requires-allocation* - whether a 'Datum' referring to this type requires //: memory allocation. Note that for externally represented string or //: arrays, meta-data may still need to be allocated. // ///User Defined Types /// - - - - - - - - - // 'Datum' exposes a type 'DatumUdt' with which a user can arbitrarily expand // the set of types a 'Datum' can support. A 'DatumUdt' object hold a void // pointer, and an integer value identifying the type. A 'DatumUdt' object is // always treated as an external reference, and the memory it refers to is not // released by 'Datum::destroy', or deep-copied by 'clone'. The meaning of the // integer type identifier is determined by the application, which is // responsible for ensuring the set of "user-defined" type identifiers remains // unique. From the viewpoint of 'Datum' a UDT is an opaque pointer with an // integer value that holds no defined meaning. In that sense it is more akin // akin to a 'void' pointer than to any of the other kind of values a 'Datum' // may hold. All knowledge of what the pointer and integer value means is // elsewhere, in the application that created the UDT. // ///Map and IntMap Types /// - - - - - - - - - - // Datum provides two 'map' types, map (datatype 'e_MAP') and int-map ( // datatype 'e_INT_MAP'). These types provide a mapping of key to value, as // represented by a sequence of key-value pairs (and are not directly related // to 'std::map'). The key types for map and int-map are 'bslstl::StringRef' // and 'int' respectively, and the value is always a 'Datum'. Both map types // keep track of whether they are sorted by key. Key-based lookup is done via // the 'find' function. If the map is in a sorted state, 'find' has O(logN) // complexity and 'find' is O(N) otherwise (where N is the number of elements // in the map). If entries with duplicate keys are present, which matching // entry will be found is unspecified. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Basic Use of 'bdld::Datum' ///- - - - - - - - - - - - - - - - - - - // This example illustrates the construction, manipulation and lifecycle of // datums. Datums are created via a set of static methods called 'createTYPE', // 'copyTYPE' or 'adoptTYPE' where TYPE is one of the supported types. The // creation methods take a value and sometimes an allocator. // // First, we create an allocator that will supply dynamic memory needed for the // 'Datum' objects being created: //.. // bslma::TestAllocator oa("object"); //.. // Then, we create a 'Datum', 'number', having an integer value of '3': //.. // Datum number = Datum::createInteger(3); //.. // Next, we verify that the created object actually represents an integer value // and verify that the value was set correctly: //.. // assert(true == number.isInteger()); // assert(3 == number.theInteger()); //.. // Note that this object does not allocate any dynamic memory on any supported // platforms and thus we do not need to explicitly destroy this object to // release any dynamic memory. // // Then, we create a 'Datum', 'cityName', having the string value "Boston": //.. // Datum cityName = Datum::copyString("Boston", strlen("Boston"), &oa); //.. // Note, that the 'copyString' makes a copy of the specified string and will // allocate memory to hold the copy. Whether the copy is stored in the object // internal storage buffer or in memory obtained from the allocator depends on // the length of the string and the platform. // // Next, we verify that the created object actually represents a string value // and verify that the value was set correctly: //.. // assert(true == cityName.isString()); // assert("Boston" == cityName.theString()); //.. // Finally, we destroy the 'cityName' object to deallocate memory used to hold // string value: //.. // Datum::destroy(cityName, &oa); //.. // ///Example 2: Creating a 'Datum' Referring to an Array of 'Datum' Objects ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This example demonstrates the construction of the 'Datum' object referring // to an existing array of 'Datum' object. // // First, we create array of the 'Datum' object: //.. // const char theDay[] = "Birthday"; // const Datum array[2] = { Datum::createDate(bdlt::Date(2015, 10, 15)), // Datum::createStringRef(StringRef(theDay), &oa) }; //.. // Note, that in this case, the second element of the array does not make a // copy of the string, but represents a string reference. // // Then, we create a 'Datum' that refers to the array of Datums: //.. // const Datum arrayRef = Datum::createArrayReference(array, 2, &oa); //.. // Next, we verify that the created 'Datum' represents the array value and that // elements of this array can be accessed. We also verify that the object // refers to external data: //.. // assert(true == arrayRef.isArray()); // assert(true == arrayRef.isExternalReference()); // assert(2 == arrayRef.theArray().length()); // assert(array[0] == arrayRef.theArray().data()[0]); // assert(array[1] == arrayRef.theArray().data()[1]); //.. // Then, we call 'destroy' on 'arrayRef', releasing any memory it may have // allocated, and verify that the external array is intact: //.. // Datum::destroy(arrayRef, &oa); // // assert(bdlt::Date(2015, 10, 15) == array[0].theDate()); // assert("Birthday" == array[1].theString()); //.. // Finally, we need to deallocate memory that was potentially allocated for the // (external) 'Datum' string in the external 'array': //.. // Datum::destroy(array[1], &oa); //.. // ///Example 3: Creating a 'Datum' with an Array Value ///- - - - - - - - - - - - - - - - - - - - - - - - - // The following example illustrates the construction of an owned array of // datums. // // *WARNING*: Using corresponding builder components is a preferred way of // constructing 'Datum' array objects. This example shows how a user-facing // builder component might use the primitives provided in 'bdld_datum'. // // First we create an array of datums: //.. // DatumMutableArrayRef bartArray; // Datum::createUninitializedArray(&bartArray, 3, &oa); // bartArray.data()[0] = Datum::createStringRef("Bart", &oa); // bartArray.data()[1] = Datum::createStringRef("Simpson", &oa); // bartArray.data()[2] = Datum::createInteger(10); // *bartArray.length() = 3; //.. // Then, we construct the Datum that holds the array itself: //.. // Datum bart = Datum::adoptArray(bartArray); //.. // Note that after the 'bartArray' has been adopted, the 'bartArray' object can // be destroyed without invalidating the array contained in the datum. // // A DatumArray may be adopted by only one datum. If the DatumArray is not // adopted, it must be destroyed via 'disposeUnitializedArray'. // // Now, we can access the contents of the array through the datum: //.. // assert(3 == bart.theArray().length()); // assert("Bart" == bart.theArray()[0].theString()); //.. // Finally, we destroy the datum, which releases all memory associated with the // array: //.. // Datum::destroy(bart, &oa); //.. // Note that the same allocator must be used to create the array, the // elements, and to destroy the datum. // ///Example 4: Creating a 'Datum' with a Map Value /// - - - - - - - - - - - - - - - - - - - - - - - // The following example illustrates the construction of a map of datums // indexed by string keys. // // *WARNING*: Using corresponding builder components is a preferred way of // constructing 'Datum' map objects. This example shows how a user-facing // builder component might use the primitives provided in 'bdld_datum'. // // First we create a map of datums: //.. // DatumMutableMapRef lisaMap; // Datum::createUninitializedMap(&lisaMap, 3, &oa); // lisaMap.data()[0] = DatumMapEntry(StringRef("firstName"), // Datum::createStringRef("Lisa", &oa)); // lisaMap.data()[1] = DatumMapEntry(StringRef("lastName"), // Datum::createStringRef("Simpson", &oa)); // lisaMap.data()[2] = DatumMapEntry(StringRef("age"), // Datum::createInteger(8)); // *lisaMap.size() = 3; //.. // Then, we construct the Datum that holds the map itself: //.. // Datum lisa = Datum::adoptMap(lisaMap); //.. // Note that after the 'lisaMap' has been adopted, the 'lisaMap' object can be // destroyed without invalidating the map contained in the datum. // // A 'DatumMutableMapRef' may be adopted by only one datum. If the // 'DatumMutableMapRef' is not adopted, it must be destroyed via // 'disposeUninitializedMap'. // // Now, we can access the contents of the map through the datum: //.. // assert(3 == lisa.theMap().size()); // assert("Lisa" == lisa.theMap().find("firstName")->theString()); //.. // Finally, we destroy the datum, which releases all memory associated with the // array: //.. // Datum::destroy(lisa, &oa); //.. // Note that the same allocator must be used to create the map, the elements, // and to destroy the datum. // ///Example 5: Mass Destruction ///- - - - - - - - - - - - - - // The following example illustrates an important idiom: the en masse // destruction of a series of datums allocated in an arena. //.. // { // // scope // bsls::AlignedBuffer<200> bufferStorage; // bdlma::BufferedSequentialAllocator arena(bufferStorage.buffer(), 200); // // Datum patty = Datum::copyString("Patty Bouvier", // strlen("Patty Bouvier"), // &arena); // // Datum selma = Datum::copyString("Selma Bouvier", // strlen("Selma Bouvier"), // &arena); // DatumMutableArrayRef maggieArray; // Datum::createUninitializedArray(&maggieArray, 2, &arena); // maggieArray.data()[0] = Datum::createStringRef("Maggie", &arena); // maggieArray.data()[1] = Datum::createStringRef("Simpson", &arena); // *maggieArray.length() = 2; // Datum maggie = Datum::adoptArray(maggieArray); // } // end of scope //.. // Here all the allocated memory is lodged in the 'arena' allocator. At the end // of the scope the memory is freed in a single step. Calling 'destroy' for // each datum individually is neither necessary nor permitted. // ///Example 6: User-defined, error and binary types ///- - - - - - - - - - - - - - - - - - - - - - - - // Imagine we are using 'Datum' within an expression evaluation subsystem. // Within that subsystem, along with the set of types defined by // 'Datum::DataType' we also need to hold 'Sequence' and 'Choice' types within // 'Datum' values (which are not natively represented by 'Datum'). First, we // define the set of types used by our subsystem that are an extension to the // types in 'DatumType': //.. // struct Sequence { // struct Sequence *d_next_p; // int d_value; // }; // // enum ExtraExpressionTypes { // e_SEQUENCE = 5, // e_CHOICE = 6 // }; //.. // Notice that the numeric values will be provided as the 'type' attribute when // constructing 'Datum' object. // // Then we create a 'Sequence' object, and create a 'Datum' to hold it (note // that we've created the object on the stack for clarity): //.. // Sequence sequence; // const Datum datumS0 = Datum::createUdt(&sequence, e_SEQUENCE); // assert(true == datumS0.isUdt()); //.. // Next, we verify that the 'datumS0' refers to the external 'Sequence' object: //.. // bdld::DatumUdt udt = datumS0.theUdt(); // assert(e_SEQUENCE == udt.type()); // assert(&sequence == udt.data()); //.. // Then, we create a 'Datum' to hold a 'DatumError', consisting of an error // code and an error description message: //.. // enum { e_FATAL_ERROR = 100 }; // Datum datumError = Datum::createError(e_FATAL_ERROR, "Fatal error.", &oa); // assert(true == datumError.isError()); // DatumError error = datumError.theError(); // assert(e_FATAL_ERROR == error.code()); // assert("Fatal error." == error.message()); // Datum::destroy(datumError, &oa); //.. // Finally, we create a 'Datum' that holds an arbitrary binary data: //.. // int buffer[] = { 1, 2, 3 }; // Datum datumBlob = Datum::copyBinary(buffer, sizeof(buffer), &oa); // buffer[2] = 666; // assert(true == datumBlob.isBinary()); // DatumBinaryRef blob = datumBlob.theBinary(); // assert(blob.size() == 3 * sizeof(int)); // assert(reinterpret_cast<const int*>(blob.data())[2] == 3); // Datum::destroy(datumBlob, &oa); //.. // Note that the bytes have been copied. #include <bdlscm_version.h> #include <bdld_datumbinaryref.h> #include <bdld_datumerror.h> #include <bdld_datumudt.h> #include <bdlb_float.h> // 'isSignalingNan' #include <bdlb_printmethods.h> #include <bdldfp_decimal.h> #include <bdlt_date.h> #include <bdlt_datetime.h> #include <bdlt_datetimeinterval.h> #include <bdlt_epochutil.h> #include <bdlt_time.h> #include <bsl_algorithm.h> #include <bslmf_assert.h> #include <bslmf_isbitwisemoveable.h> #include <bslmf_istriviallycopyable.h> #include <bslmf_istriviallydefaultconstructible.h> #include <bslmf_nestedtraitdeclaration.h> #include <bslmf_nil.h> #include <bsls_alignedbuffer.h> #include <bsls_annotation.h> #include <bsls_assert.h> #include <bsls_performancehint.h> #include <bsls_platform.h> #include <bsls_review.h> #include <bsls_types.h> #include <bsl_climits.h> #include <bsl_cstring.h> #include <bsl_iosfwd.h> #include <bsl_limits.h> #include <bsl_string.h> #include <bsl_utility.h> #include <bslma_allocator.h> #if !defined(BSLS_PLATFORM_CPU_32_BIT) && !defined(BSLS_PLATFORM_CPU_64_BIT) #error 'bdld::Datum' supports 32- or 64-bit platforms only. BSLS_PLATFORM_COMPILER_ERROR; #endif #if defined(BSLS_PLATFORM_CMP_MSVC) #define BDLD_DATUM_FORCE_INLINE __forceinline #elif defined(BSLS_PLATFORM_CMP_GNU) #define BDLD_DATUM_FORCE_INLINE inline #else #define BDLD_DATUM_FORCE_INLINE inline #endif namespace BloombergLP { namespace bdld { class DatumArrayRef; class DatumIntMapEntry; class DatumIntMapRef; class DatumMapEntry; class DatumMapRef; class DatumMutableArrayRef; class DatumMutableIntMapRef; class DatumMutableMapOwningKeysRef; class DatumMutableMapRef; // =========== // class Datum // =========== class Datum { // This class implements a mechanism that provides a space-efficient // discriminated union that holds the value of ether scalar type or an // aggregate of 'Datum' objects. The size of 'Datum' is 8 bytes (same as a // 'double') on 32-bit platforms and 16 bytes on 64-bit platforms. // Separate representation are needed on 32 and 64 bit platforms because of // the differing size of a pointer (a 64-bit pointer cannot reasonably be // held in a 32-bit footprint). // // Representation on a 32-bit Platforms: Values are stored inside an 8-byte // unsigned char array ('d_data'). Any 'double' value (including NaN and // infinity values) can be stored inside 'Datum'. When storing a value of // a type other than 'double', the bits in 'd_data' that correspond to the // exponent part of a 'double' value are set to 1, with the 4 bits in the // fraction part used to indicate the type of value stored. // // Representation on 64-bit platforms: Values are stored inside a 16 byte // unsigned char array ('d_data') to store values. The type information is // stored in the upper 2 bytes of the character array. Remaining 14 bytes // are used to store the actual value or the pointer to the external memory // that holds the value. // // For details on the internal representations that are used for various // types on 32 and 64 bit platforms, please see the implementation notes in // 'bdld_datum.cpp'. // // Datum objects are bitwise copyable and have trivial initialization, // assignment and destruction. Only one of the copies of the same 'Datum' // object can be passed to 'destroy'. The rest of those copies then become // invalid and it is undefined behavior to deep-copy or destroy them. // Although, these copies can be used on the left hand side of assignment. public: // TYPES enum DataType { // Enumeration used to discriminate among the different externally- // exposed types of values that can be stored inside 'Datum'. e_NIL = 0 // null value , e_INTEGER = 1 // integer value , e_DOUBLE = 2 // double value , e_STRING = 3 // string value , e_BOOLEAN = 4 // boolean value , e_ERROR = 5 // error value , e_DATE = 6 // date value , e_TIME = 7 // time value , e_DATETIME = 8 // datetime value , e_DATETIME_INTERVAL = 9 // datetime interval value , e_INTEGER64 = 10 // 64-bit integer value , e_USERDEFINED = 11 // pointer to a user-defined object , e_ARRAY = 12 // array reference , e_MAP = 13 // map reference , e_BINARY = 14 // pointer to the binary data , e_DECIMAL64 = 15 // Decimal64 , e_INT_MAP = 16 // integer map reference #ifndef BDE_OMIT_INTERNAL_DEPRECATED , e_REAL = e_DOUBLE // old spelling , e_ERROR_VALUE = e_ERROR , DLCT_NIL = e_NIL , DLCT_INTEGER = e_INTEGER , DLCT_REAL = e_DOUBLE , DLCT_STRING = e_STRING , DLCT_BOOLEAN = e_BOOLEAN , DLCT_ERROR_VALUE = e_ERROR_VALUE , DLCT_DATE = e_DATE , DLCT_TIME = e_TIME , DLCT_DATETIME = e_DATETIME , DLCT_DATETIME_INTERVAL = e_DATETIME_INTERVAL , DLCT_INTEGER64 = e_INTEGER64 , DLCT_USERDEFINED = e_USERDEFINED , DLCT_ARRAY = e_ARRAY , DLCT_MAP = e_MAP , DLCT_BINARY = e_BINARY , DLCT_DECIMAL64 = e_DECIMAL64 #endif }; enum { // Define 'k_NUM_TYPES' to be the number of consecutively valued // enumerators in the range '[ e_NIL .. e_DECIMAL64 ]'. k_NUM_TYPES = 17 // number of distinct enumerated types #ifndef BDE_OMIT_INTERNAL_DEPRECATED , DLCT_NUM_TYPES = k_NUM_TYPES #endif }; #if defined(BSLS_PLATFORM_CPU_32_BIT) private: // PRIVATE TYPES // 32-bit variation enum InternalDataType { // Enumeration used to discriminate among the different types of values // that can be stored inside 'Datum'. e_INTERNAL_INF = 0 // +/- infinity value , e_INTERNAL_LONGEST_SHORTSTRING = 1 // 6 character string , e_INTERNAL_BOOLEAN = 2 // boolean value , e_INTERNAL_SHORTSTRING = 3 // short string value , e_INTERNAL_STRING = 4 // string value , e_INTERNAL_DATE = 5 // date value , e_INTERNAL_TIME = 6 // time value , e_INTERNAL_DATETIME = 7 // date+time value , e_INTERNAL_DATETIME_INTERVAL = 8 // date+time interval value , e_INTERNAL_INTEGER = 9 // integer value , e_INTERNAL_INTEGER64 = 10 // 64-bit integer value , e_INTERNAL_USERDEFINED = 11 // pointer to a user-defined obj , e_INTERNAL_ARRAY = 12 // array of datums , e_INTERNAL_STRING_REFERENCE = 13 // unowned string , e_INTERNAL_ARRAY_REFERENCE = 14 // unowned array of , e_INTERNAL_EXTENDED = 15 // extended data types , e_INTERNAL_DOUBLE = 16 // double value }; enum { // Define 'k_NUM_INTERNAL_TYPES' to be the number of consecutively // valued enumerators in the range // '[ e_INTERNAL_INF .. e_INTERNAL_DOUBLE ]'. k_NUM_INTERNAL_TYPES = 17 // number of internal types }; enum ExtendedInternalDataType { // Enumeration used to discriminate among different types of values // that map on to the 'e_INTERNAL_EXTENDED' discriminator value inside // 'Datum'. It is used to add any new required types. e_EXTENDED_INTERNAL_MAP = 0 // map of datums keyed by string // values that are not owned , e_EXTENDED_INTERNAL_OWNED_MAP = 1 // map of datums keyed by string // values that are owned , e_EXTENDED_INTERNAL_NAN2 = 2 // NaN double value , e_EXTENDED_INTERNAL_ERROR = 3 // error with code only , e_EXTENDED_INTERNAL_ERROR_ALLOC = 4 // error with code and // description string // We never need to externally allocate the reference types with the // 64-bit implementation because we can fit 32 bits of length inline. , e_EXTENDED_INTERNAL_SREF_ALLOC = 5 // allocated string ref , e_EXTENDED_INTERNAL_AREF_ALLOC = 6 // allocated array ref , e_EXTENDED_INTERNAL_DATETIME_ALLOC = 7 // allocated datetime , e_EXTENDED_INTERNAL_DATETIME_INTERVAL_ALLOC = 8 // allocated datetime // interval , e_EXTENDED_INTERNAL_INTEGER64_ALLOC = 9 // 64-bit integer value , e_EXTENDED_INTERNAL_BINARY_ALLOC = 10 // binary data , e_EXTENDED_INTERNAL_DECIMAL64 = 11 // Decimal64 , e_EXTENDED_INTERNAL_DECIMAL64_SPECIAL = 12 // Decimal64 NaN of Inf , e_EXTENDED_INTERNAL_DECIMAL64_ALLOC = 13 // allocated Decimal64 , e_EXTENDED_INTERNAL_NIL = 14 // null value , e_EXTENDED_INTERNAL_INT_MAP = 15 // map of datums keyed by // 32-bit integer values }; enum { // Define 'k_NUM_EXTENDED_INTERNAL_TYPES' to be the number of // consecutively valued enumerators in the range // '[ e_EXTENDED_INTERNAL_MAP .. e_EXTENDED_INTERNAL_INT_MAP ]'. k_NUM_EXTENDED_INTERNAL_TYPES = 16 // number of distinct enumerated // extended types }; // PRIVATE CLASS DATA // 32-bit variation static const unsigned short k_DOUBLE_MASK = 0x7ff0U; // mask value to be // stored in the // exponent part of // 'd_data' to // indicate a special // 'double' value static const int k_SHORTSTRING_SIZE = 6; // maximum size of short strings // stored in the internal storage // buffer static const int k_TYPE_MASK_BITS = 16; // number of bits the internal // data type needs to be shifted // into place static const short k_DATETIME_OFFSET_FROM_EPOCH = 18262; // Number of days offset from 1970 Jan 1 used to create the epoch used // to determine if 'Datum' stores a date-time value using dynamic // memory allocation or withing the 'Datum' itself. This offset, added // to the 1970 Jan 1 date, creates an (mid) epoch of 2020 Jan 1. // Given that 'Datum' uses a signed 16 bits day-offset when storing // date-time internally, the 2020 Jan 1 epoch enables of storing // date-times internally the range of 1930 Apr 15 to 2109 Sept 18. // Note that the time part of date-time can be stored internally // without data loss, so that makes the no-allocation range to be // 1930 Apr 15 00:00:00.000000 to 2109 Sept 18 24:00:00.000000. See // 'createDatetime' and 'theDatetime' methods for the implementation. #ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN // Check if platform is little endian. static const int k_EXPONENT_OFFSET = 6; // offset of the exponent part in // the internal storage buffer static const int k_EXPONENT_LSB = k_EXPONENT_OFFSET; // Low Byte static const int k_EXPONENT_MSB = k_EXPONENT_OFFSET + 1; // High Byte static const int k_DATA_OFFSET = 0; // offset of the data part in the // internal storage buffer static const int k_SHORTSTRING_OFFSET = 0;// offset of short-strings stored // in the internal storage buffer static const int k_SHORT_OFFSET = 4; // offset of (2 byte values like) // discriminator values for // extended types and information // for user-defined objects in // the internal storage buffer static const int k_MASK_OFFSET = 4; // offset of the special mask // value in the internal storage // buffer static const int k_NEARDATE_OFFSET = 4; // offset of the short date // offset from now value in the // internal storage buffer static const int k_TIME_OFFSET = 0; // offset of the time value in // the internal storage buffer #else // BSLS_PLATFORM_IS_LITTLE_ENDIAN // Check if platform is big endian. static const int k_EXPONENT_OFFSET = 0; // offset of the exponent part in // the internal storage buffer static const int k_EXPONENT_LSB = k_EXPONENT_OFFSET + 1; // Low Byte static const int k_EXPONENT_MSB = k_EXPONENT_OFFSET; // High Byte static const int k_DATA_OFFSET = 4; // offset of the data part in the // internal storage buffer static const int k_SHORTSTRING_OFFSET = 2;// offset of short-strings stored // in the internal storage buffer static const int k_SHORT_OFFSET = 2; // offset of (2 byte values like) // discriminator values for // extended types and information // for user-defined objects in // the internal storage buffer static const int k_MASK_OFFSET = 0; // offset of the special mask // value in the internal storage // buffer static const int k_NEARDATE_OFFSET = 2; // offset of the short date // offset from now value in the // internal storage buffer static const int k_TIME_OFFSET = 4; // offset of the time value in // the internal storage buffer #endif enum { // Enumeration used to discriminate between the special incompressible // Decimal64 values. e_DECIMAL64_SPECIAL_NAN, e_DECIMAL64_SPECIAL_INFINITY, e_DECIMAL64_SPECIAL_NEGATIVE_INFINITY }; // DATA // 32-bit variation struct ShortString5 { // Storage for a string shorter than 6 chars and its length. #ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN char d_chars[5]; // the string's characters char d_length; // the string's length unsigned short d_exponent; // the exponent inside the double #else unsigned short d_exponent; // the exponent inside the double char d_chars[5]; // the string's characters char d_length; // the string's length #endif }; struct ShortString6 { // Storage for a string of exactly 6 chars. Length is implicit. #ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN char d_chars[6]; // the string's characters unsigned short d_exponent; // the exponent inside the double #else unsigned short d_exponent; // the exponent inside the double char d_chars[6]; // the string's characters #endif }; struct TypedAccess { // Storage for various combinations of short, int and pointer. // TYPE FIELDS // --------------- ------------------------------- // Null d_short = extended type // // Boolean d_int = value // // Integer d_int = value // // String d_cvp = allocated memory containing copy // (length > 6) of string preceded by length // // StringRef d_ushort = length // (length < USHORT_MAX) d_cvp = pointer to the c-string // // StringRef d_short = extended type // (length >= USHORT_MAX) d_cvp = pointer to allocated memory // containing pointer to the c-string // preceded by c-string length // // Date d_int = value // // Time d_int = value // // Datetime d_short = days from now // (near offset) d_int = time part // // Datetime d_short = extended type // (far offset) d_cvp = pointer to allocated value // // // DatetimeInterval d_short = upper 16 bits // (short) d_int = lower 32 // // DatetimeInterval d_short = extended type // (long) d_cvp = pointer to allocated value // // Error d_short = extended type // (code only) d_int = value // // Error d_short = extended type // (code + error string) d_cvp = pointer to allocated memory // containing: code, length, c-string // // Udt d_ushort = udt type // d_cvp = pointer to udt object // // ArrayReference d_ushort = length // (length < USHORT_MAX) d_cvp = pointer to array // // ArrayReference // (length >= USHORT_MAX) d_short = extended type // d_cvp = pointer to allocated memory // containing: pointer to array, // length // // Map d_short = extended type // d_cvp = pointer to allocated memory // containing: length, sorted flag, // array of map entries // // Int-map d_short = extended type // d_cvp = pointer to allocated memory // containing: length, sorted flag, // array of int-map entries // // Binary: d_short = extended type // d_cvp = pointer to allocated memory // containing: length, binary copy #ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN union { int d_int; // as integer value const void *d_cvp; // as const void* value }; union { short d_short; // as signed short value unsigned short d_ushort; // as unsigned short value }; unsigned short d_exponent; // the exponent inside the double #else unsigned short d_exponent; // the exponent inside the double union { short d_short; // as signed short value unsigned short d_ushort; // as unsigned short }; union { int d_int; // as integer value const void *d_cvp; // as const void* value }; #endif }; struct ExponentAccess { // For accessing exponent as a word, for better performance. #ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN unsigned int d_dummy; unsigned int d_value; // the exponent as a 32 bit word #else unsigned int d_value; // the exponent as a 32 bit word unsigned int d_dummy; #endif }; // Internal Datum representation union { // Do not change the order of these member, otherwise the code will not // work properly with the clang compiler. char d_data[8]; // as a byte array of internal storage ShortString5 d_string5; // as a string shorter than 5 chars ShortString6 d_string6; // as a string of exactly 6 chars TypedAccess d_as; // as a combination of pointer, int and // short ExponentAccess d_exp; // as the exponent as a 32 bit word double d_double; // as a double value }; // PRIVATE CLASS METHODS // 32-bit variation static Datum createExtendedDataObject(ExtendedInternalDataType type, void *data); static Datum createExtendedDataObject(ExtendedInternalDataType type, int data); // Return a datum by copying the specified 'data' of the specified // 'type'. Note that the pointer value in 'data' is copied and the // pointed object is not cloned. // PRIVATE ACCESSORS // 32-bit variation ExtendedInternalDataType extendedInternalType() const; // Return the extended type of the value stored in this object (which // cannot be represented by the 4-bit discriminator 'InternalDataType') // as one of the enumeration values defined in // 'ExtendedInternalDataType'. DataType typeFromExtendedInternalType() const; // Return the type of the value stored in this object as one of the // enumeration values defined in 'DataType' (mapped from the // 'ExtendedInternalDataType' value). bsls::Types::Int64 theLargeInteger64() const; // Return the 64-bit integer value stored in the allocated storage. DatumArrayRef theLongArrayReference() const; // Return the array referenced by this object. The behavior is // undefined unless this object references an array with 'length >= // USHORT_MAX'. bslstl::StringRef theLongestShortString() const; // Return the short string value stored in this object as a // 'bslstl::StringRef' object. The behavior is undefined unless this // object actually stores a short string value. bslstl::StringRef theLongStringReference() const; // Return the string referenced by this object. The behavior is // undefined unless this object holds a reference to a string with // 'length >= USHORT_MAX'. bsls::Types::Int64 theSmallInteger64() const; // Return the 64-bit integer value stored inline in this object. #else // defined(BSLS_PLATFORM_CPU_32_BIT) private: // PRIVATE TYPES enum InternalDataType { // Enumeration used to discriminate among the different types of values // that can be stored inside 'Datum'. e_INTERNAL_UNINITIALIZED = 0, // zero-filled Datums are invalid e_INTERNAL_INF = 1, // +/- infinity value e_INTERNAL_NIL = 2, // null value e_INTERNAL_BOOLEAN = 3, // boolean value e_INTERNAL_SHORTSTRING = 4, // short string value e_INTERNAL_STRING = 5, // string value e_INTERNAL_DATE = 6, // date value e_INTERNAL_TIME = 7, // time value e_INTERNAL_DATETIME = 8, // date+time value e_INTERNAL_DATETIME_INTERVAL = 9, // date+time interval value e_INTERNAL_INTEGER = 10, // integer value e_INTERNAL_INTEGER64 = 11, // 64-bit integer value e_INTERNAL_USERDEFINED = 12, // pointer to a user-defined object e_INTERNAL_ARRAY = 13, // array of datums e_INTERNAL_STRING_REFERENCE = 14, // not owned string e_INTERNAL_ARRAY_REFERENCE = 15, // not owned array e_INTERNAL_DOUBLE = 16, // double value e_INTERNAL_MAP = 17, // map of datums keyed by string // values that are not owned e_INTERNAL_OWNED_MAP = 18, // map of datums keyed by string // values that are owned e_INTERNAL_ERROR = 19, // error code, internal storage e_INTERNAL_ERROR_ALLOC = 20, // error code, allocated storage e_INTERNAL_BINARY = 21, // binary data, internal storage e_INTERNAL_BINARY_ALLOC = 22, // binary data, allocated storage e_INTERNAL_DECIMAL64 = 23, // Decimal64 e_INTERNAL_INT_MAP = 24 // map of datums keyed by 32-bit // integer values }; enum { // Define 'k_NUM_INTERNAL_TYPES' to be the number of consecutively // valued enumerators in the range // '[ e_INTERNAL_UNINITIALIZED .. e_INTERNAL_DECIMAL64 ]'. k_NUM_INTERNAL_TYPES = 25 // number of internal types }; // CLASS DATA // 64-bit variation static const int k_TYPE_OFFSET = 14; // offset of type in the // internal storage // buffer static const int k_SHORTSTRING_SIZE = 13; // maximum size of short // strings that stored in // the internal storage // buffer static const int k_SMALLBINARY_SIZE_OFFSET = 13; // offset of the size of // small-size binaries // stored in the internal // storage buffer static const int k_SMALLBINARY_SIZE = 13; // maximum size of // small-size binaries // stored in the internal // storage buffer // DATA // 64-bit variation struct TypedAccess { // Typed access to the bits of the 'Datum' internal representation union { // Offset: 0 bsls::Types::Int64 d_int64; void *d_ptr; double d_double; }; int d_int32; // Offset: 8 short d_filler; // Offset: 12 short d_type; // Offset: 14 }; union { // Ensures proper alignment (16 byte) and provides 2 types of access to // the 64-bit 'Datum' internal representation. The 'd_data' array // allows us raw access to the bytes; while 'd_as' provides typed // access to the individual "data compartments". bsls::AlignedBuffer<16> d_data; TypedAccess d_as; }; // PRIVATE CLASS METHODS // 64-bit variation static Datum createDatum(InternalDataType type, void *data); // Create a 'Datum' object of the specified 'type' with the specified // 'data' value. static Datum createDatum(InternalDataType type, int data); // Create a 'Datum' object of the specified 'type' with the specified // 'data' value. // PRIVATE ACCESSORS // 64-bit variation void* theInlineStorage(); // Return a pointer to the internal storage buffer const void* theInlineStorage() const; // Return a non-modifiable pointer to the internal storage buffer. #endif // defined(BSLS_PLATFORM_CPU_32_BIT) private: // FRIENDS friend bool operator==(const Datum& lhs, const Datum& rhs); friend bool operator!=(const Datum& lhs, const Datum& rhs); friend bsl::ostream& operator<<(bsl::ostream& stream, const Datum& rhs); // PRIVATE CLASS METHODS static void destroyMemory(const Datum& value, bslma::Allocator *basicAllocator); // Deallocate any memory that was previously allocated for the // specified 'value' using the specified 'basicAllocator'. // PRIVATE ACCESSORS InternalDataType internalType() const; // Return the internal type of value stored in this object as one of // the enumeration values defined in 'InternalDataType'. DatumArrayRef theArrayReference() const; // Return the array reference represented by this object as // 'DatumArrayRef' object. The behavior is undefined unless the object // represents an array reference whose size is stored in the object // internal storage buffer. Note that all array references store their // size in the object internal storage buffer on 64-bit platforms. DatumArrayRef theInternalArray() const; // Return the array represented by this object as 'DatumArrayRef' // object. The behavior is undefined unless the object represents an // array of 'Datum's. bslstl::StringRef theInternalString() const; // Return the string value represented by this object as a // 'bslstl::StringRef' object. The behavior is undefined unless the // object represents an internal (non-reference, non-short) string. bslstl::StringRef theShortString() const; // Return the short string value represented by this object as a // 'bslstl::StringRef' object. The behavior is undefined unless the // object actually represents a short string value. bslstl::StringRef theStringReference() const; // Return the string reference represented by this object as a // 'bslstl::StringRef' object. The behavior is undefined unless the // object represents a string reference whose size is stored in the // object internal storage buffer. Note that the size always stored in // the object internal storage buffer on 64-bit platforms. public: // TYPES typedef bsls::Types::size_type SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the capacity of a datum array, the capacity of a datum map, the // capacity of the *keys-capacity* of a datum-key-owning map or the // length of a string. // CLASS METHODS static Datum createArrayReference(const Datum *array, SizeType length, bslma::Allocator *basicAllocator); // Return, by value, a datum referring to the specified 'array', // having the specified 'length', using the specified 'basicAllocator' // to supply memory (if needed). 'array' is not copied, and is not // freed when the returned object is destroyed with 'Datum::destroy'. // The behavior is undefined unless 'array' contains at least 'length' // elements. The behavior is also undefined unless 'length < // UINT_MAX'. static Datum createArrayReference(const DatumArrayRef& value, bslma::Allocator *basicAllocator); // Return, by value, a datum having the specified 'value', using the // specified 'basicAllocator' to supply memory (if needed). The array // referenced by 'value' is not copied, and is not freed if // 'Datum::destroy' is called on the returned object. The behavior is // undefined unless 'value.length() < UINT_MAX'. static Datum createBoolean(bool value); // Return, by value, a datum having the specified 'bool' 'value'. static Datum createDate(const bdlt::Date& value); // Return, by value, a datum having the specified 'Date' 'value'. static Datum createDatetime(const bdlt::Datetime& value, bslma::Allocator *basicAllocator); // Return, by value, a datum having the specified 'Datetime' 'value', // using the specified 'basicAllocator' to supply memory (if needed). static Datum createDatetimeInterval( const bdlt::DatetimeInterval& value, bslma::Allocator *basicAllocator); // Return, by value, a datum holding the specified 'DatetimeInterval' // 'value', using the specified 'basicAllocator' to supply memory (if // needed). static Datum createDecimal64(bdldfp::Decimal64 value, bslma::Allocator *basicAllocator); // Return, by value, a datum having the specified 'Decimal64' 'value', // using the specified 'basicAllocator' to supply memory (if needed). // Note that the argument is passed by value because it is assumed to // be a fundamental type. static Datum createDouble(double value); // Return, by value, a datum having the specified 'double' 'value'. // When 'value' is NaN this method guarantees only that a NaN value is // stored. The sign and NaN payload bits of a NaN 'value' later // retrieved by the 'theDouble' method are unspecified (see also // {Special Floating Point Values}. static Datum createError(int code); // Return, by value, a datum having a 'DatumError' value with the // specified 'code'. static Datum createError(int code, const bslstl::StringRef& message, bslma::Allocator *basicAllocator); // Return, by value, a datum having a 'DatumError' value with the // specified 'code' and the specified 'message', using the specified // 'basicAllocator' to supply memory (if needed). static Datum createInteger(int value); // Return, by value, a datum having the specified 'int' 'value'. static Datum createInteger64(bsls::Types::Int64 value, bslma::Allocator *basicAllocator); // Return, by value, a datum having the specified 'Integer64' 'value', // using the specified 'basicAllocator' to supply memory (if needed). static Datum createNull(); // Return, by value, a datum having no value. static Datum createStringRef(const char *string, SizeType length, bslma::Allocator *basicAllocator); // Return, by value, a datum that refers to the specified 'string' // having the specified 'length', using the specified 'basicAllocator' // to supply memory (if needed). The behavior is undefined unless // '0 != string || 0 == length'. The behavior is also undefined // unless 'length < UINT_MAX'. Note that 'string' is not copied, and // is not freed if 'Datum::destroy' is called on the returned object. static Datum createStringRef(const char *string, bslma::Allocator *basicAllocator); // Return, by value, a datum that refers to the specified 'string', // using the specified 'basicAllocator' to supply memory (if needed). // The behavior is undefined unless 'string' points to a UTF-8 encoded // c-string. The behavior is also undefined unless 'strlen(string) < // UINT_MAX'. Note that 'string' is not copied, and is not freed if // 'Datum::destroy' is called on the returned object. static Datum createStringRef(const bslstl::StringRef& value, bslma::Allocator *basicAllocator); // Return, by value, a datum having the specified 'StringRef' 'value', // using the specified 'basicAllocator' to supply memory (if needed). // The behavior is undefined unless 'value.length() < UINT_MAX'. Note // that 'string' is not copied, and is not freed if 'Datum::destroy' is // called on the returned object. static Datum createTime(const bdlt::Time& value); // Return, by value, a datum having the specified 'Time' 'value'. static Datum createUdt(void *data, int type); // Return, by value, a datum having the 'DatumUdt' value with the // specified 'data' and the specified 'type' values. The behavior is // undefined unless '0 <= type <= 65535'. Note that 'data' is held, // not owned. Also note that the content pointed to by 'data' object // is not copied. static Datum copyBinary(const void *value, SizeType size, bslma::Allocator *basicAllocator); // Return, by value, a datum referring to the copy of the specified // 'value' of the specified 'size', using the specified // 'basicAllocator' to supply memory (if needed). The behavior is // undefined unless 'size < UINT_MAX'. Note that the copy of the // binary data is owned and will be freed if 'Datum::destroy' is called // on the returned object. static Datum copyString(const char *string, SizeType length, bslma::Allocator *basicAllocator); // Return, by value, a datum that refers to the copy of the specified // 'string' having the specified 'length', using the specified // 'basicAllocator' to supply memory (if needed). The behavior is // undefined unless '0 != string || 0 == length'. The behavior is also // undefined unless 'length < UINT_MAX'. Note that the copied string // is owned and will be freed if 'Datum::destroy' is called on the // returned object. static Datum copyString(const bslstl::StringRef& value, bslma::Allocator *basicAllocator); // Return, by value, a datum having the copy of the specified // 'StringRef' 'value', using the specified 'basicAllocator' to supply // memory (if needed). The behavior is undefined unless // 'value.length() < UINT_MAX'. Note that the copied string is owned, // and will be freed if 'Datum::destroy' is called on the returned // object. static Datum adoptArray(const DatumMutableArrayRef& array); // Return, by value, a datum that refers to the specified 'array'. The // behavior is undefined unless 'array' was created using // 'createUninitializedArray' method. The behavior is also undefined // unless each element in the held datum array has been assigned a // value and the array's length has been set accordingly. Note that // the adopted array is owned and will be freed if 'Datum::destroy' is // called on the returned object. static Datum adoptIntMap(const DatumMutableIntMapRef& intMap); // Return, by value, a datum that refers to the specified 'intMap'. // The behavior is undefined unless 'map' was created using // 'createUninitializedIntMap' method. The behavior is also undefined // unless each element in the held map has been assigned a value and // the size of the map has been set accordingly. Note that the adopted // map is owned and will be freed if 'Datum::destroy' is called on the // returned object. static Datum adoptMap(const DatumMutableMapRef& map); // Return, by value, a datum that refers to the specified 'map'. The // behavior is undefined unless 'map' was created using // 'createUninitializedMap' method. The behavior is also undefined // unless each element in the held map has been assigned a value and // the size of the map has been set accordingly. Note that the adopted // map is owned and will be freed if 'Datum::destroy' is called on the // returned object. static Datum adoptMap(const DatumMutableMapOwningKeysRef& map); // Return, by value, a datum that refers to the specified 'map'. The // behavior is undefined unless 'map' was created using // 'createUninitializedMapOwningKeys' method. The behavior is also // undefined unless each element in the held map has been assigned a // value and the size of the map has been set accordingly. The // behavior is also undefined unless keys have been copied into the // map. Note that the adopted map is owned and will be freed if // 'Datum::destroy' is called on the returned object. static void createUninitializedArray(DatumMutableArrayRef *result, SizeType capacity, bslma::Allocator *basicAllocator); // Load the specified 'result' with a reference to a newly created // datum array having the specified 'capacity', using the specified // 'basicAllocator' to supply memory. The behavior is undefined if // 'capacity' 'Datum' objects would exceed the addressable memory for // the platform. Note that the caller is responsible for filling in // elements into the datum array and setting its length accordingly. // The number of elements in the datum array cannot exceed 'capacity'. // Also note that any elements in the datum array that need dynamic // memory must be allocated with 'basicAllocator'. static void createUninitializedIntMap( DatumMutableIntMapRef *result, SizeType capacity, bslma::Allocator *basicAllocator); // Load the specified 'result' with a reference to a newly created // datum int-map having the specified 'capacity', using the specified // 'basicAllocator' to supply memory. The behavior is undefined if // 'capacity' 'DatumIntMapEntry' objects would exceed the addressable // memory for the platform. Note that the caller is responsible for // filling in elements into the datum int-map and setting its size // accordingly. The number of elements in the datum int-map cannot // exceed 'capacity'. Also note that any elements in the datum int-map // that need dynamic memory, should also be allocated with // 'basicAllocator'. static void createUninitializedMap(DatumMutableMapRef *result, SizeType capacity, bslma::Allocator *basicAllocator); // Load the specified 'result' with a reference to a newly created // datum map having the specified 'capacity', using the specified // 'basicAllocator' to supply memory. The behavior is undefined if // 'capacity' 'DatumMapEntry' objects would exceed the addressable // memory for the platform. Note that the caller is responsible for // filling in elements into the datum map and setting its size // accordingly. The number of elements in the datum map cannot exceed // 'capacity'. Also note that any elements in the datum map that need // dynamic memory, should also be allocated with 'basicAllocator'. static void createUninitializedMap( DatumMutableMapOwningKeysRef *result, SizeType capacity, SizeType keysCapacity, bslma::Allocator *basicAllocator); // Load the specified 'result' with a reference to a newly created // datum-key-owning map having the specified 'capacity' and // 'keysCapacity', using the specified 'basicAllocator' to supply // memory. The behavior is undefined if 'capacity' 'DatumMapEntry' // objects plus 'keysCapacity' would exceed the addressable memory for // the platform. Note that the caller is responsible for filling in // elements into the datum-key-owning map, copying the keys into it, // and setting its size accordingly. The number of elements in the // datum-key-owning map cannot exceed 'capacity' and total size of all // the keys cannot exceed 'keysCapacity'. Also note that any elements // in the datum-key-owning map that need dynamic memory, should also be // allocated with 'basicAllocator'. static char *createUninitializedString(Datum *result, SizeType length, bslma::Allocator *basicAllocator); // Load the specified 'result' with a reference to a newly created // character buffer of the specified 'length', using the specified // 'basicAllocator' to supply memory, and return the address of this // buffer. The behavior is undefined unless 'length < UINT_MAX'. Note // that the caller is responsible for initializing the returned buffer // with a UTF-8 encoded string. static const char *dataTypeToAscii(DataType type); // Return the non-modifiable string representation corresponding to the // specified 'type', if it exists, and a unique (error) string // otherwise. The string representation of 'type' matches its // corresponding enumerator name with the 'e_' prefix elided. // // For example: //.. // bsl::cout << bdld::Datum::dataTypeToAscii(bdld::Datum::e_NIL); //.. // will print the following on standard output: //.. // NIL //.. // Note that specifying a 'type' that does not match any of the // enumerators will result in a string representation that is distinct // from any of those corresponding to the enumerators, but is otherwise // unspecified. static void destroy(const Datum& value, bslma::Allocator *basicAllocator); // Deallocate any memory that was previously allocated within the // specified 'value' using the specified 'basicAllocator'. If the // 'value' contains an adopted array of datums, 'destroy' is called on // each array element. If the 'value' contains an adopted map of // datums, 'destroy' is called on each map element. The behavior is // undefined unless all dynamically allocated memory owned by 'value' // was allocated using 'basicAllocator', and has not previously been // released by a call to 'destroy', either on this object, or on // another object referring to same contents as this object (i.e., only // one copy of a 'Datum' object can be destroyed). The behavior is // also undefined if 'value' has an uninitialized or partially // initialized array or map (created using 'createUninitializedArray', // 'createUninitializedMap' or 'createUninitializeMapOwningKeys'). // Note that after this operation completes, 'value' is left in an // uninitialized state, and must be assigned a new value before being // accessed again. static void disposeUninitializedArray( const DatumMutableArrayRef& array, bslma::Allocator *basicAllocator); // Deallocate the memory used by the specified 'array' (but *not* // memory allocated for its contained elements) using the specified // 'basicAllocator'. This method does not destroy individual array // elements and the memory allocated for those elements must be // explicitly deallocated before calling this method. The behavior is // undefined unless 'array' was created with 'createUninitializedArray' // using 'basicAllocator'. static void disposeUninitializedIntMap( const DatumMutableIntMapRef& intMap, bslma::Allocator *basicAllocator); // Deallocate the memory used by the specified 'intMap' (but *not* // memory allocated for its contained elements) using the specified // 'basicAllocator'. This method does not destroy individual map // elements and the memory allocated for those elements must be // explicitly deallocated before calling this method. The behavior is // undefined unless 'map' was created with 'createUninitializedIntMap' // using 'basicAllocator'. static void disposeUninitializedMap( const DatumMutableMapRef& map, bslma::Allocator *basicAllocator); static void disposeUninitializedMap( const DatumMutableMapOwningKeysRef& map, bslma::Allocator *basicAllocator); // Deallocate the memory used by the specified 'map' (but *not* memory // allocated for its contained elements) using the specified // 'basicAllocator'. This method does not destroy individual map // elements and the memory allocated for those elements must be // explicitly deallocated before calling this method. The behavior is // undefined unless 'map' was created with 'createUninitializedMap' // using 'basicAllocator'. // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(Datum, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(Datum, bsl::is_trivially_default_constructible); BSLMF_NESTED_TRAIT_DECLARATION(Datum, bslmf::IsBitwiseMoveable); BSLMF_NESTED_TRAIT_DECLARATION(Datum, bdlb::HasPrintMethod); // CREATORS //! Datum() = default; // Create a datum having an uninitialized value. The behavior for // every accessor method is undefined until this object is assigned a // value. //! Datum(const Datum& original) = default; // Create a datum having the value of the specified 'original'. //! ~Datum() = default; // Destroy this object. Note that this method does not deallocate any // dynamically allocated memory used by this object (see 'destroy'). // MANIPULATORS //! Datum& operator=(const Datum& rhs) = default; // Assign to this object the value of the specified 'rhs' object. Note // that this method's definition is compiler generated. // ACCESSORS template <class BDLD_VISITOR> void apply(BDLD_VISITOR& visitor) const; // Apply the specified 'visitor' to the current value represented by // this object by passing held value to the 'visitor' object's // 'operator()' overload. Datum clone(bslma::Allocator *basicAllocator) const; // Return a datum holding a "deep-copy" of this object, using the // specified 'basicAllocator' to supply memory. This method creates an // independent deep-copy of the data of this object, including any // referenced data, with the exception of {User Defined Types}. For // further information see {Deep Copying}. // Type-Identifiers bool isArray() const; // Return 'true' if this object represents an array of 'Datum's and // 'false' otherwise. bool isBinary() const; // Return 'true' if this object represents a binary value and 'false' // otherwise. bool isBoolean() const; // Return 'true' if this object represents a boolean value and 'false' // otherwise. bool isDate() const; // Return 'true' if this object represents a 'bdlt::Date' value and // 'false' otherwise. bool isDatetime() const; // Return 'true' if this object represents a 'bdlt::Datetime' value and // 'false' otherwise. bool isDatetimeInterval() const; // Return 'true' if this object represents a 'bdlt::DatetimeInterval' // value and 'false' otherwise. bool isDecimal64() const; // Return 'true' if this object represents a 'bdlfpd::Decimal64' value // and 'false' otherwise. bool isDouble() const; // Return 'true' if this object represents a 'double' value and 'false' // otherwise. bool isError() const; // Return 'true' if this object represents a 'DatumError' value and // 'false' otherwise. bool isExternalReference() const; // Return 'true' if this object represents a reference to an externally // managed array, string or user-defined object and 'false' otherwise. // If this method returns 'false', calling 'destroy' on this object // will release the memory used by the array, string, or used-defined // object as well as any meta-data directly used by this datum (e.g., // length information); otherwise (if this method returns 'true') // calling 'destroy' on this object will release any allocated // meta-data, but will not impact the externally managed array, string, // or user-defined object. bool isInteger() const; // Return 'true' if this object represents an integer value and 'false' // otherwise. bool isInteger64() const; // Return 'true' if this object represents a 'Int64' value and 'false' // otherwise. bool isIntMap() const; // Return 'true' if this object represents a map of datums that are // keyed by 32-bit int values and 'false' otherwise. bool isMap() const; // Return 'true' if this object represents a map of datums that are // keyed by string values and 'false' otherwise. bool isNull() const; // Return 'true' if this object represents no value and 'false' // otherwise. bool isString() const; // Return 'true' if this object represents a string value and 'false' // otherwise. bool isTime() const; // Return 'true' if this object represents a 'bdlt::Time' value and // 'false' otherwise. bool isUdt() const; // Return 'true' if this object represents a 'DatumUdt' value and // 'false' otherwise. // Type-Accessors DatumArrayRef theArray() const; // Return the array value represented by this object as a // 'DatumArrayRef' object. The behavior is undefined unless this // object actually represents an array of datums. DatumBinaryRef theBinary() const; // Return the binary reference represented by this object as a // 'DatumBinaryRef' object. The behavior is undefined unless this // object actually represents a binary reference. bool theBoolean() const; // Return the boolean value represented by this object. The behavior // is undefined unless this object actually represents a 'bool' value. bdlt::Date theDate() const; // Return the date value represented by this object as a 'bdlt::Date' // object. The behavior is undefined unless this object actually // represents a date value. bdlt::Datetime theDatetime() const; // Return the date+time value represented by this object as a // 'bdlt::Datetime' object. The behavior is undefined unless this // object actually represents date+time value. bdlt::DatetimeInterval theDatetimeInterval() const; // Return the date+time interval value represented by this object as a // 'bdlt::DatetimeInterval'. The behavior is undefined unless this // object actually represents a date+time interval value. bdldfp::Decimal64 theDecimal64() const; // Return the decimal floating point value represented by this object // as a 'bdlfpd::Decimal64' value. The behavior is undefined unless // this object actually represents a decimal floating point value. double theDouble() const; // Return the double value represented by this object. The behavior is // undefined unless this object actually represents a double value. // If the returned value is NaN this method guarantees only that a NaN // value will be returned. The sign and NaN payload bits of NaN values // returned are unspecified (see also {Special Floating Point Values}. DatumError theError() const; // Return the error value represented by this object as a 'DatumError' // value. The behavior is undefined unless this object actually // represents an error value. int theInteger() const; // Return the integer value represented by this object. The behavior // is undefined unless this object actually represents an integer // value. bsls::Types::Int64 theInteger64() const; // Return the 64-bit integer value represented by this object as a // 'Int64' value. The behavior is undefined unless this object // actually represents a 64-bit integer value. DatumIntMapRef theIntMap() const; // Return the int-map value represented by this object as a // 'DatumIntMapRef' object. The behavior is undefined unless this // object actually represents an int-map of datums. DatumMapRef theMap() const; // Return the map value represented by this object as a 'DatumMapRef' // object. The behavior is undefined unless this object actually // represents a map of datums. bslstl::StringRef theString() const; // Return the string value represented by this object as a // 'bslstl::StringRef' object. The behavior is undefined unless this // object actually represents a string value. bdlt::Time theTime() const; // Return the time value represented by this object as a 'bdlt::Time' // object. The behavior is undefined unless this object actually // represents a time value. DatumUdt theUdt() const; // Return the user-defined object represented by this object as a // 'DatumUdt' object. The behavior is undefined unless this object // actually represents a user-defined object. DataType type() const; // Return the type of value represented by this object as one of the // enumeration values defined in 'DataType'. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Write the value of this object to the specified output 'stream' in a // human-readable format, and return a reference to the modifiable // 'stream'. Optionally specify an initial indentation 'level', whose // absolute value is incremented recursively for nested objects. If // 'level' is specified, optionally specify 'spacesPerLevel', whose // absolute value indicates the number of spaces per indentation level // for this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. Note that this // human-readable format is not fully specified, and can change without // notice. #ifndef BDE_OMIT_INTERNAL_DEPRECATED // DEPRECATED static void createUninitializedMapOwningKeys( DatumMutableMapOwningKeysRef *result, SizeType capacity, SizeType keysCapacity, bslma::Allocator *basicAllocator); // [!DEPRECATED!] Use 'createUninitializedMap' instead. static Datum adoptMapOwningKeys( const DatumMutableMapOwningKeysRef& mapping); // [!DEPRECATED!] Use 'adoptMap' instead. static void disposeUninitializedMapOwningKeys( const DatumMutableMapOwningKeysRef& mapping, bslma::Allocator *basicAllocator); // [!DEPRECATED!] Use 'disposeUninitializedMap' instead. #endif }; // FREE OPERATORS bool operator==(const Datum& lhs, const Datum& rhs); // Return 'true' if the specified 'lhs' and 'rhs' represent the same value, // and 'false' otherwise. Two datums (not holding strings and user- // defined objects) represent the same value if they have the same type of // value stored inside them and invoking '==' operator on the stored values // returns 'true'. Two datums holding strings are equal if the strings // have the same length and and values at each respective character // position are also same. Two datums holding user-defined objects are // equal if the user-defined objects have the same pointer and type values. // Two 'nil' datums are always equal. Two 'Datum' objects holding 'NaN' // values are never equal. Two datums that hold arrays of datums have the // same value if the underlying arrays have the same length and invoking // '==' operator on each corresponding element returns 'true'. Two datums // that hold maps of datums have the same value if the underlying maps have // the same size and each corresponding pair of elements in the maps have // the same keys and invoking '==' operator on the values returns 'true'. bool operator!=(const Datum& lhs, const Datum& rhs); // Return 'true' if the specified 'lhs' and 'rhs' datums do not represent // the same value, and 'false' otherwise. Two datums do not represent the // same value if they do not hold values of the same type, or they hold // values of the same type but invoking '==' operator on the stored values // returns 'false'. Two strings do not have the same value if they have // different lengths or values at one of the respective character position // are not the same. Two 'DatumUdt' objects are not equal if they have // different pointer or type values. Two 'bdemf_Nil' values are always // equal. Two datums with 'NaN' values are never equal. Two datums that // hold arrays of datums have different values if the underlying arrays // have different lengths or invoking '==' operator on at least one of the // corresponding pair of contained elements returns 'false'. Two datums // that hold maps of datums have different values if the underlying maps // have different sizes or at least one of the corresponding pair of // elements in the maps have different keys or invoking '==' operator on // the values returns 'false'. bsl::ostream& operator<<(bsl::ostream& stream, const Datum& rhs); // Write the specified 'rhs' value to the specified output 'stream' in the // format shown in the second column in the table below (based on the type // of value stored, indicated by the first column): //.. // null - nil // // bool - true/false // // DatumError - error(code)/error(code, 'msg') // where 'code' is the integer error code and // 'msg' is the error description message // // int - plain integer value // // Int64 - plain Int64 value // // double - plain double value // // string - plain double-quoted string value // // array - [ elem0, ..., elemN] // where elem1..elemN are output for individual // array elements // // int-map - [key0 = val0, ..., keyN = valN] // where keyX and valX are respectively key and // value of the map entry elements of the map // // map - [key0 = val0, ..., keyN = valN] // where keyX and valX are respectively key and // value of the map entry elements of the map // // bdlt::Date - ddMONyyyy // // bdlt::Time - hh:mm:ss.sss // // bdlt::Datetime - ddMONyyyy_hh:mm:ss.sss // // bdlt::DatetimeInterval - sDD_HH:MM:SS.SSS (where s is the sign(+/-)) // // DatumUdt - user-defined(address,type) // where 'address' is a hex encoded pointer to // the user-defined object and 'type' is its type //.. // and return a reference to the modifiable 'stream'. The function will // have no effect if the specified 'stream' is not valid. template <class HASH_ALGORITHM> void hashAppend(HASH_ALGORITHM& hashAlgorithm, const Datum& datum); // Invoke the specified 'hashAlgorithm' on the value of the specified // 'datum' object. Note that the value of a User Defined Type in Datum is // a combination of its type integer and the address (pointer value), not // the actual value of the object that the pointer points to. bsl::ostream& operator<<(bsl::ostream& stream, Datum::DataType rhs); // Write the string representation of the specified enumeration 'rhs' to // the specified 'stream' in a single-line format, and return a reference // to the modifiable 'stream'. See 'dataTypeToAscii' for what constitutes // the string representation of a 'Datum::DataType' value. // ========================== // class DatumMutableArrayRef // ========================== class DatumMutableArrayRef { // This 'class' provides mutable access to a datum array. The users of // this class can read from and assign to the individual elements as well // as change the length of the array. public: // TYPES typedef Datum::SizeType SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the capacity of a datum array. private: // DATA Datum *d_data_p; // pointer to an array (not owned) SizeType *d_length_p; // pointer to the length of the array public: // CREATORS DatumMutableArrayRef(); // Create a 'DatumMutableArrayRef' object that refers to no array. DatumMutableArrayRef(Datum *data, SizeType *length); // Create a 'DatumMutableArrayRef' object having the specified 'data' // and 'length'. //! DatumMutableArrayRef(const DatumMutableArrayRef& original) = default; // Create a 'DatumMutableArrayRef' having the value of the specified // 'original' object. Note that this method's definition is compiler // generated. //! ~DatumMutableArrayRef() = default; // Destroy this object. Note that this method's definition is compiler // generated. // MANIPULATORS //! DatumMutableArrayRef& operator=( //! const DatumMutableArrayRef& rhs) = default; // Assign to this object the value of the specified 'rhs' object. Note // that this method's definition is compiler generated. // ACCESSORS Datum *data() const; // Return pointer to the first element of the held array. SizeType *length() const; // Return pointer to the length of the array. }; // ========================= // struct Datum_IntMapHeader // ========================= struct Datum_IntMapHeader { // This component-local class provides a layout of the meta-information // stored in front of the Datum int-maps. // DATA Datum::SizeType d_size; // size of the map bool d_sorted; // sorted flag }; // ====================== // struct Datum_MapHeader // ====================== struct Datum_MapHeader { // This component-local class provides a layout of the meta-information // stored in front of the Datum maps. // DATA Datum::SizeType d_size; // size of the map bool d_sorted; // sorted flag bool d_ownsKeys; // owns keys flag }; // ======================== // class DatumMutableMapRef // ======================== class DatumMutableMapRef { // This 'class' provides a mutable access to a datum map. The users of // this class can assign to the individual elements and also change the // size of the map. public: typedef Datum::SizeType SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the capacity of a datum array, the capacity of a datum map, the // capacity of the *keys-capacity* of a datum-key-owning map or the // length of a string. private: // DATA DatumMapEntry *d_data_p; // pointer to a map of datums (not owned) SizeType *d_size_p; // pointer to the size of the map bool *d_sorted_p; // pointer to flag indicating whether the map // is sorted or not public: // CREATORS DatumMutableMapRef(); // Create a 'DatumMutableMapRef' object. DatumMutableMapRef(DatumMapEntry *data, SizeType *size, bool *sorted); // Create a 'DatumMutableMapRef' object having the specified 'data', // 'size', and 'sorted'. //! DatumMutableMapRef(const DatumMutableMapRef& original) = default; // Create a 'DatumMutableMapRef' having the value of the specified // 'original' object. Note that this method's definition is compiler // generated. //! ~DatumMutableMapRef() = default; // Destroy this object. Note that this method's definition is compiler // generated. // MANIPULATORS //! DatumMutableMapRef& operator=(const DatumMutableMapRef& rhs) = default; // Assign to this object the value of the specified 'rhs' object. Note // that this method's definition is compiler generated. // ACCESSORS DatumMapEntry *data() const; // Return pointer to the first element in the (held) map. SizeType *size() const; // Return pointer to the location where the (held) map's size is // stored. bool *sorted() const; // Return pointer to the location where the (held) map's *sorted* flag // is stored. }; // =========================== // class DatumMutableIntMapRef // =========================== class DatumMutableIntMapRef { // This 'class' provides a mutable access to a datum int-map. The users of // this class can assign to the individual elements and also change the // size of the map. public: typedef Datum::SizeType SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the capacity of a datum array, the capacity of a datum map, the // capacity of the *keys-capacity* of a datum-key-owning map or the // length of a string. private: // DATA DatumIntMapEntry *d_data_p; // pointer to an int-map of datums (not // owned) SizeType *d_size_p; // pointer to the size of the map bool *d_sorted_p; // pointer to flag indicating whether the // int-map is sorted or not public: // CREATORS DatumMutableIntMapRef(); // Create a 'DatumMutableIntMapRef' object. DatumMutableIntMapRef(DatumIntMapEntry *data, SizeType *size, bool *sorted); // Create a 'DatumMutableIntMapRef' object having the specified 'data', // 'size', and 'sorted'. //! DatumMutableIntMapRef(const DatumMutableIntMapRef& original) = default; // Create a 'DatumMutableIntMapRef' having the value of the specified // 'original' object. Note that this method's definition is compiler // generated. //! ~DatumMutableIntMapRef() = default; // Destroy this object. Note that this method's definition is compiler // generated. // MANIPULATORS //! DatumMutableIntMapRef& operator=(const DatumMutableIntMapRef& rhs) //! = default; // Assign to this object the value of the specified 'rhs' object. Note // that this method's definition is compiler generated. // ACCESSORS DatumIntMapEntry *data() const; // Return pointer to the first element in the (held) map. SizeType *size() const; // Return pointer to the location where the (held) map's size is // stored. bool *sorted() const; // Return pointer to the location where the (held) map's *sorted* flag // is stored. }; // ================================== // class DatumMutableMapOwningKeysRef // ================================== class DatumMutableMapOwningKeysRef { // This 'class' provides mutable access to a datum key-owning map. The // users of this class can assign to the individual elements, copy keys and // change the size of the map. public: typedef Datum::SizeType SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the capacity of a datum array, the capacity of a datum map, the // capacity of the *keys-capacity* of a datum-key-owning map or the // length of a string. private: // DATA DatumMapEntry *d_data_p; // pointer to a map of datums (not owned) SizeType *d_size_p; // pointer to the size of the map char *d_keys_p; // pointer to the key storage bool *d_sorted_p; // pointer to flag indicating whether the map // is sorted or not public: // CREATORS DatumMutableMapOwningKeysRef(); // Create a 'DatumMutableMapOwningKeysRef' object. DatumMutableMapOwningKeysRef(DatumMapEntry *data, SizeType *size, char *keys, bool *sorted); // Create a 'DatumMutableMapOwningKeysRef' object having the specified // 'data', 'size', 'keys', and 'sorted'. //! DatumMutableMapOwningKeysRef( //! const DatumMutableMapOwningKeysRef& original) = default; // Create a 'DatumMutableMapOwningKeysRef' having the value of the // specified 'original' object. Note that this method's definition is // compiler generated. //!~DatumMutableMapOwningKeysRef() = default; // Destroy this object. Note that this method's definition is compiler // generated. // MANIPULATORS //! DatumMutableMapOwningKeysRef& operator=( //! const DatumMutableMapOwningKeysRef& rhs) = default; // Assign to this object the value of the specified 'rhs' object. Note // that this method's definition is compiler generated. // ACCESSORS DatumMapEntry *data() const; // Return pointer to the first element in the held map. char *keys() const; // Return pointer to the start of the buffer where keys are stored. SizeType *size() const; // Return pointer to the location where the (held) map's size is // stored. bool *sorted() const; // Return pointer to the location where the (held) map's *sorted* flag // is stored. }; // =================== // class DatumArrayRef // =================== class DatumArrayRef { // This 'class' provides a read-only view to an array of datums. It holds // the array by a 'const' pointer and an integral length value. It acts as // return value for accessors inside the 'Datum' class that return an array // of datums. Note that zero-length arrays are valid. public: typedef Datum::SizeType SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the length of a datum array. private: // DATA const Datum *d_data_p; // pointer to the first array element (not owned) SizeType d_length; // length of the array of public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(DatumArrayRef, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(DatumArrayRef, bdlb::HasPrintMethod); // CREATORS DatumArrayRef(); // Create a 'DatumArrayRef' object representing an empty array. DatumArrayRef(const Datum *data, SizeType length); // Create a 'DatumArrayRef' object having the specified 'data' and // 'length'. The behavior is undefined unless '0 != data' or '0 == // length'. Note that the pointer to the array is just copied. //! DatumArrayRef(const DatumArrayRef& other) = default; // Create a 'DatumArrayRef' object having the value of the specified // 'original' object. Note that this method's definition is compiler // generated. //! ~DatumArrayRef() = default; // Destroy this object. Note that this method's definition is compiler // generated. // MANIPULATORS //! DatumArrayRef& operator=(const DatumArrayRef& rhs) = default; // Assign to this object the value of the specified 'rhs' object. Note // that this method's definition is compiler generated. // ACCESSORS const Datum& operator[](SizeType index) const; // Return the element stored at the specified 'index' position in this // array. const Datum *data() const; // Return pointer to the first array element. SizeType length() const; // Return the length of the array. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Write the value of this object to the specified output 'stream' in a // human-readable format, and return a reference to the modifiable // 'stream'. Optionally specify an initial indentation 'level', whose // absolute value is incremented recursively for nested objects. If // 'level' is specified, optionally specify 'spacesPerLevel', whose // absolute value indicates the number of spaces per indentation level // for this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. Note that this // human-readable format is not fully specified, and can change without // notice. }; // FREE OPERATORS bool operator==(const DatumArrayRef& lhs, const DatumArrayRef& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and // 'false' otherwise. Two 'DatumArrayRef' objects have the same value if // they hold arrays of the same length and all the corresponding 'Datum' // objects in the two arrays also compare equal. bool operator!=(const DatumArrayRef& lhs, const DatumArrayRef& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have different values, // and 'false' otherwise. Two 'DatumArrayRef' objects have different // values if they hold arrays of different lengths or invoking operator // '==' returns false for at least one of the corresponding elements in the // arrays. bsl::ostream& operator<<(bsl::ostream& stream, const DatumArrayRef& rhs); // Write the specified 'rhs' value to the specified output 'stream' in the // format shown below: //.. // [aa,bb,cc] - aa, bb and cc are the result of invoking operator '<<' // on the individual elements in the array //.. // and return a reference to the modifiable 'stream'. The function will // have no effect if the 'stream' is not valid. // ====================== // class DatumIntMapEntry // ====================== class DatumIntMapEntry { // This class represents an entry in a datum map keyed by string values. BSLMF_ASSERT(sizeof(int) == 4 && CHAR_BIT == 8); private: // DATA int d_key; // key for this entry Datum d_value; // value for this entry public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(DatumIntMapEntry, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(DatumIntMapEntry, bdlb::HasPrintMethod); // CREATORS DatumIntMapEntry(); // Create a 'DatumIntMapEntry' object. DatumIntMapEntry(int key, const Datum& value); // Create a 'DatumIntMapEntry' object using the specified 'key' and // 'value'. //!~DatumIntMapEntry() = default; // MANIPULATORS void setKey(int key); // Set the key for this entry to the specified 'key'. void setValue(const Datum& value); // Set the value for this entry to the specified 'value'. // ACCESSORS int key() const; // Return the key for this entry. const Datum& value() const; // Return the value for this entry. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Write the value of this object to the specified output 'stream' in a // human-readable format, and return a reference to the modifiable // 'stream'. Optionally specify an initial indentation 'level', whose // absolute value is incremented recursively for nested objects. If // 'level' is specified, optionally specify 'spacesPerLevel', whose // absolute value indicates the number of spaces per indentation level // for this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. Note that this // human-readable format is not fully specified, and can change without // notice. }; // FREE OPERATORS bool operator==(const DatumIntMapEntry& lhs, const DatumIntMapEntry& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and // 'false' otherwise. Two 'DatumIntMapEntry' objects have the same value // if their keys and values compare equal. bool operator!=(const DatumIntMapEntry& lhs, const DatumIntMapEntry& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have different values, // and 'false' otherwise. Two 'DatumIntMapEntry' objects have different // values if either the keys or values are not equal. bsl::ostream& operator<<(bsl::ostream& stream, const DatumIntMapEntry& rhs); // Write the specified 'rhs' value to the specified output 'stream' in the // format shown below: //.. // (nnn,aa) - nnn is key integer, while aa is the result of invoking // operator '<<' on the value //.. // and return a reference to the modifiable 'stream'. The function will // have no effect if the 'stream' is not valid. // ==================== // class DatumIntMapRef // ==================== class DatumIntMapRef { // This class provides a read-only view to a map of datums (an array of // 'DatumIntMapEntry' objects). It holds the array by a 'const' pointer // and an integral size value. It acts as return value for accessors // inside the 'Datum' class that return a map of 'Datum' objects. Note // that zero-size maps are valid. public: typedef Datum::SizeType SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the capacity of a datum array, the capacity of a datum map, the // capacity of the *keys-capacity* of a datum-key-owning map or the // length of a string. private: // DATA const DatumIntMapEntry *d_data_p; // pointer to the array of // 'DatumIntMapEntry' objects (not // owned) SizeType d_size; // length of the array bool d_sorted; // flag indicating whether the array is // sorted or not public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(DatumIntMapRef, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(DatumIntMapRef, bdlb::HasPrintMethod); // CREATORS DatumIntMapRef(const DatumIntMapEntry *data, SizeType size, bool sorted); // Create a 'DatumIntMapRef' object having the specified 'data' of the // specified 'size' and the specified 'sorted' flag. The behavior is // undefined unless '0 != data' or '0 == size'. Note that the pointer // to the array is just copied. //!~DatumIntMapRef() = default; // ACCESSORS const DatumIntMapEntry& operator[](SizeType index) const; // Return the element stored at the specified 'index' position in this // map. The behavior is undefined unless 'index < size()'. const DatumIntMapEntry *data() const; // Return pointer to the first element in the map. bool isSorted() const; // Return 'true' if underlying map is sorted and 'false' otherwise. SizeType size() const; // Return the size of the map. const Datum *find(int key) const; // Return a const pointer to the datum having the specified 'key', if // it exists and 0 otherwise. Note that the 'find' has order of 'O(n)' // if the data is not sorted based on the keys; if the data is sorted, // it has order of 'O(log(n))'. Also note that if multiple entries // with matching keys are present, which matching record is found is // unspecified. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Write the value of this object to the specified output 'stream' in a // human-readable format, and return a reference to the modifiable // 'stream'. Optionally specify an initial indentation 'level', whose // absolute value is incremented recursively for nested objects. If // 'level' is specified, optionally specify 'spacesPerLevel', whose // absolute value indicates the number of spaces per indentation level // for this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. Note that this // human-readable format is not fully specified, and can change without // notice. }; // FREE OPERATORS bool operator==(const DatumIntMapRef& lhs, const DatumIntMapRef& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and // 'false' otherwise. Two 'DatumIntMapRef' objects have the same value if // they hold maps of the same size and all the corresponding // 'DatumIntMapEntry' elements in the two maps also compare equal. bool operator!=(const DatumIntMapRef& lhs, const DatumIntMapRef& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have different values, // and 'false' otherwise. Two 'DatumIntMapRef' objects have different // values if they hold maps of different sizes or operator '==' returns // 'false' for at least one of the corresponding elements in the maps. bsl::ostream& operator<<(bsl::ostream& stream, const DatumIntMapRef& rhs); // Write the specified 'rhs' value to the specified output 'stream' in the // format shown below: //.. // [ nnn = aa, mmm = bb] - nnn and mmm are key ints, while aa and bb // are the result of invoking operator '<<' on the // individual value elements in the map //.. // and return a reference to the modifiable 'stream'. The function will // have no effect if the 'stream' is not valid. // =================== // class DatumMapEntry // =================== class DatumMapEntry { // This class represents an entry in a datum map keyed by string values. private: // DATA bslstl::StringRef d_key_p; // key for this entry (not owned) Datum d_value; // value for this entry public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(DatumMapEntry, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(DatumMapEntry, bdlb::HasPrintMethod); // CREATORS DatumMapEntry(); // Create a 'DatumMapEntry' object. DatumMapEntry(const bslstl::StringRef& key, const Datum& value); // Create a 'DatumMapEntry' object using the specified 'key' and // 'value'. //!~DatumMapEntry() = default; // MANIPULATORS void setKey(const bslstl::StringRef& key); // Set the key for this entry to the specified 'key'. void setValue(const Datum& value); // Set the value for this entry to the specified 'value'. // ACCESSORS const bslstl::StringRef& key() const; // Return the key for this entry. const Datum& value() const; // Return the value for this entry. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Write the value of this object to the specified output 'stream' in a // human-readable format, and return a reference to the modifiable // 'stream'. Optionally specify an initial indentation 'level', whose // absolute value is incremented recursively for nested objects. If // 'level' is specified, optionally specify 'spacesPerLevel', whose // absolute value indicates the number of spaces per indentation level // for this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. Note that this // human-readable format is not fully specified, and can change without // notice. }; // FREE OPERATORS bool operator==(const DatumMapEntry& lhs, const DatumMapEntry& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and // 'false' otherwise. Two 'DatumMapEntry' objects have the same value if // their keys and values compare equal. bool operator!=(const DatumMapEntry& lhs, const DatumMapEntry& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have different values, // and 'false' otherwise. Two 'DatumMapEntry' objects have different // values if either the keys or values are not equal. bsl::ostream& operator<<(bsl::ostream& stream, const DatumMapEntry& rhs); // Write the specified 'rhs' value to the specified output 'stream' in the // format shown below: //.. // (abc,aa) - abc is key string, while aa is the result of invoking // operator '<<' on the value //.. // and return a reference to the modifiable 'stream'. The function will // have no effect if the 'stream' is not valid. // ================= // class DatumMapRef // ================= class DatumMapRef { // This class provides a read-only view to a map of datums (an array of // 'DatumMapEntry' objects). It holds the array by a 'const' pointer and // an integral size value. It acts as return value for accessors inside // the 'Datum' class that return a map of 'Datum' objects. Note that // zero-size maps are valid. public: typedef Datum::SizeType SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the capacity of a datum array, the capacity of a datum map, the // capacity of the *keys-capacity* of a datum-key-owning map or the // length of a string. private: // DATA const DatumMapEntry *d_data_p; // pointer to the array of 'DatumMapEntry' // objects (not owned) SizeType d_size; // length of the array bool d_sorted; // flag indicating whether the array is // sorted or not bool d_ownsKeys; // flag indicating whether the map owns // the keys or not public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(DatumMapRef, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(DatumMapRef, bdlb::HasPrintMethod); // CREATORS DatumMapRef(const DatumMapEntry *data, SizeType size, bool sorted, bool ownsKeys); // Create a 'DatumMapRef' object having the specified 'data' of the // specified 'size' and the specified 'sorted' and 'ownsKeys' flags. // The behavior is undefined unless '0 != data' or '0 == size'. Note // that the pointer to the array is just copied. //!~DatumMapRef() = default; // ACCESSORS const DatumMapEntry& operator[](SizeType index) const; // Return the element stored at the specified 'index' position in this // map. The behavior is undefined unless 'index < size()'. const DatumMapEntry *data() const; // Return pointer to the first element in the map. bool isSorted() const; // Return 'true' if underlying map is sorted and 'false' otherwise. bool ownsKeys() const; // Return 'true' if underlying map owns the keys and 'false' otherwise. // Note that 'false' is always returned for zero-sized 'DatumMapRef'. SizeType size() const; // Return the size of the map. const Datum *find(const bslstl::StringRef& key) const; // Return a const pointer to the datum having the specified 'key', if // it exists and 0 otherwise. Note that the 'find' has order of 'O(n)' // if the data is not sorted based on the keys. If the data is sorted, // it has order of 'O(log(n))'. Also note that if multiple entries // with matching keys are present, which matching record is found is // unspecified. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Write the value of this object to the specified output 'stream' in a // human-readable format, and return a reference to the modifiable // 'stream'. Optionally specify an initial indentation 'level', whose // absolute value is incremented recursively for nested objects. If // 'level' is specified, optionally specify 'spacesPerLevel', whose // absolute value indicates the number of spaces per indentation level // for this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. Note that this // human-readable format is not fully specified, and can change without // notice. }; // FREE OPERATORS bool operator==(const DatumMapRef& lhs, const DatumMapRef& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and // 'false' otherwise. Two 'DatumMapRef' objects have the same value if // they hold maps of the same size and all the corresponding // 'DatumMapEntry' elements in the two maps also compare equal. bool operator!=(const DatumMapRef& lhs, const DatumMapRef& rhs); // Return 'true' if the specified 'lhs' and 'rhs' have different values, // and 'false' otherwise. Two 'DatumMapRef' objects have different values // if they hold maps of different sizes or operator '==' returns false for // at least one of the corresponding elements in the maps. bsl::ostream& operator<<(bsl::ostream& stream, const DatumMapRef& rhs); // Write the specified 'rhs' value to the specified output 'stream' in the // format shown below: //.. // [ abc = aa, pqr = bb] - abc and pqr are key strings, while aa and bb // are the result of invoking operator '<<' on the // individual value elements in the map //.. // and return a reference to the modifiable 'stream'. The function will // have no effect if the 'stream' is not valid. // ==================== // struct Datum_Helpers // ==================== struct Datum_Helpers { // This struct contains helper functions used to access typed objects // within a buffer. The functions assume that objects within the buffers // have proper alignment and use casts to suppress compiler warnings about // possible alignment problems. template <class Type> static Type load(const void *source, int offset); // Return the typed value found at the specified 'offset' within the // specified 'source'. template <class Type> static Type store(void *destination, int offset, Type value); // Store the specified typed 'value' at the specified 'offset' within // the specified 'destination' and return 'value'. }; #if defined(BSLS_PLATFORM_CPU_32_BIT) // ====================== // struct Datum_Helpers32 // ====================== struct Datum_Helpers32 : Datum_Helpers { // This struct contains helper functions used in the 32-bit variation. The // functions are for internal use only and may change or disappear without // notice. // CLASS DATA #ifdef BSLS_PLATFORM_IS_LITTLE_ENDIAN static const int b00 = 0; // Bits 0 to 32. static const int b32 = 4; // Bits 32 to 48. static const int b48 = 6; // Bits 48 to 64. #else static const int b00 = 4; static const int b32 = 2; static const int b48 = 0; #endif // CLASS METHODS static bsls::Types::Int64 loadInt48(short high16, int low32); // Load an Int64 from the specified 'high16' and 'low32' values created // by storeSmallInt48. This method is public for testing purpose only. // It may change or be removed without notice. static bool storeInt48(bsls::Types::Int64 value, short *phigh16, int *plow32); // Store an Int64 in short at 'phigh16' and int at 'plow32' if its // highest order 16 bits are zero. Return true if it fits. This // method is public for testing purpose only. It may change or be // removed without notice. static bsls::Types::Int64 loadSmallInt64(short high16, int low32); // Load an Int64 from the specified 'high16' and 'low32' values created // by storeSmallInt64. This method is public for testing purpose only. // It may change or be removed without notice. static bool storeSmallInt64(bsls::Types::Int64 value, short *phigh16, int *plow32); // Store an Int64 in short at 'phigh16' and int at 'plow32'. Return // true if it fits. This method is public for testing purpose only. // It may change or be removed without notice. }; #endif // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // -------------------- // struct Datum_Helpers // -------------------- // CLASS METHODS template <class Type> inline Type Datum_Helpers::load(const void *source, int offset) { // The intermediate cast to 'void *' avoids warnings about the cast to a // pointer of stricter alignment. return *static_cast<const Type *>( static_cast<const void *>( static_cast<const char *>(source) + offset)); } template <class Type> inline Type Datum_Helpers::store(void *destination, int offset, Type value) { // The intermediate cast to 'void *' avoids warnings about the cast to a // pointer of stricter alignment. return *static_cast<Type *>( static_cast<void *>( static_cast<char *>(destination) + offset)) = value; } #if defined(BSLS_PLATFORM_CPU_32_BIT) // ---------------------- // struct Datum32_Helpers // ---------------------- // CLASS METHODS inline bsls::Types::Int64 Datum_Helpers32::loadSmallInt64(short high16, int low32) { bsls::Types::Int64 value; store<short>(&value, b48, store<short>(&value, b32, high16) < 0 ? -1 : 0); store<long> (&value, b00, low32); return value; } inline bool Datum_Helpers32::storeSmallInt64(bsls::Types::Int64 value, short *phigh16, int *plow32) { // Check that the sign can be inferred from the compressed 6-byte integer. // It is the case if the upper 16 bits are the same as the 17th bit. if ((load<short>(&value, b48) == 0 && load<short>(&value, b32) >= 0) || (load<short>(&value, b48) == -1 && load<short>(&value, b32) < 0)) { *phigh16 = load<short>(&value, b32); *plow32 = load<long> (&value, b00); return true; // RETURN } return false; } inline bsls::Types::Int64 Datum_Helpers32::loadInt48(short high16, int low32) { bsls::Types::Int64 value; store<short>(&value, b48, 0); store<short>(&value, b32, high16); store<long>(&value, b00, low32); return value; } inline bool Datum_Helpers32::storeInt48(bsls::Types::Int64 value, short *phigh16, int *plow32) { // Check 'value' is a 6-byte integer. It is the case if the upper 16 bits // are zero. if (load<short>(&value, b48) == 0) { *phigh16 = load<short>(&value, b32); *plow32 = load<long>(&value, b00); return true; // RETURN } return false; } #endif // BSLS_PLATFORM_CPU_32_BIT // ----------- // class Datum // ----------- // This section contains all class methods and private accessors that are used // only in implementation for specific platform. #ifdef BSLS_PLATFORM_CPU_32_BIT // PRIVATE CLASS METHODS // 32-bit only inline Datum Datum::createExtendedDataObject(ExtendedInternalDataType type, void *data) { Datum result; result.d_exp.d_value = (k_DOUBLE_MASK | e_INTERNAL_EXTENDED) << k_TYPE_MASK_BITS | type; result.d_as.d_cvp = data; return result; } inline Datum Datum::createExtendedDataObject(ExtendedInternalDataType type, int data) { Datum result; result.d_exp.d_value = (k_DOUBLE_MASK | e_INTERNAL_EXTENDED) << k_TYPE_MASK_BITS | type; result.d_as.d_int = data; return result; } // PRIVATE ACCESSORS // 32-bit only inline Datum::ExtendedInternalDataType Datum::extendedInternalType() const { BSLS_ASSERT_SAFE(e_INTERNAL_EXTENDED == internalType()); return static_cast<ExtendedInternalDataType>(d_as.d_short); } inline Datum::DataType Datum::typeFromExtendedInternalType() const { BSLS_ASSERT_SAFE(e_INTERNAL_EXTENDED == internalType()); static const DataType convert[] = { Datum::e_MAP // e_EXTENDED_INTERNAL_MAP = 0 , Datum::e_MAP // e_EXTENDED_INTERNAL_OWNED_MAP = 1 , Datum::e_DOUBLE // e_EXTENDED_INTERNAL_NAN2 = 2 , Datum::e_ERROR // e_EXTENDED_INTERNAL_ERROR = 3 , Datum::e_ERROR // e_EXTENDED_INTERNAL_ERROR_ALLOC = 4 , Datum::e_STRING // e_EXTENDED_INTERNAL_SREF_ALLOC = 5 , Datum::e_ARRAY // e_EXTENDED_INTERNAL_AREF_ALLOC = 6 , Datum::e_DATETIME // e_EXTENDED_INTERNAL_DATETIME_ALLOC = 7 , Datum::e_DATETIME_INTERVAL // e_EXTENDED_INTERNAL_DATETIME_INTERVAL_ALLOC = 8 , Datum::e_INTEGER64 // e_EXTENDED_INTERNAL_INTEGER64_ALLOC = 9 , Datum::e_BINARY // e_EXTENDED_INTERNAL_BINARY_ALLOC = 10 , Datum::e_DECIMAL64 // e_EXTENDED_INTERNAL_DECIMAL64 = 11 , Datum::e_DECIMAL64 // e_EXTENDED_INTERNAL_DECIMAL64_SPECIAL = 12 , Datum::e_DECIMAL64 // e_EXTENDED_INTERNAL_DECIMAL64_ALLOC = 13 , Datum::e_NIL // e_EXTENDED_INTERNAL_NIL = 14 , Datum::e_INT_MAP // e_EXTENDED_INTERNAL_INT_MAP = 15 }; BSLMF_ASSERT(sizeof(convert)/sizeof(convert[0]) == k_NUM_EXTENDED_INTERNAL_TYPES); const ExtendedInternalDataType type = extendedInternalType(); BSLS_ASSERT_OPT(static_cast<int>(type) < static_cast<int>(k_NUM_EXTENDED_INTERNAL_TYPES)); return convert[type]; } inline bsls::Types::Int64 Datum::theLargeInteger64() const { BSLS_ASSERT_SAFE(internalType() == e_INTERNAL_EXTENDED); BSLS_ASSERT_SAFE( extendedInternalType() == e_EXTENDED_INTERNAL_INTEGER64_ALLOC); return Datum_Helpers::load<bsls::Types::Int64>(d_as.d_cvp, 0); } inline DatumArrayRef Datum::theLongArrayReference() const { return DatumArrayRef( Datum_Helpers::load<Datum *> (d_as.d_cvp, 0), Datum_Helpers::load<SizeType>(d_as.d_cvp, sizeof(Datum *))); } inline bslstl::StringRef Datum::theLongestShortString() const { return bslstl::StringRef(d_string6.d_chars, sizeof d_string6.d_chars); } inline bslstl::StringRef Datum::theLongStringReference() const { return bslstl::StringRef( Datum_Helpers::load<char *> (d_as.d_cvp, 0), Datum_Helpers::load<SizeType>(d_as.d_cvp, sizeof(char *))); } inline bsls::Types::Int64 Datum::theSmallInteger64() const { BSLS_ASSERT_SAFE(internalType() == e_INTERNAL_INTEGER64); return Datum_Helpers32::loadSmallInt64(d_as.d_short, d_as.d_int); } #else // BSLS_PLATFORM_CPU_32_BIT // PRIVATE CLASS METHODS // 64-bit only inline Datum Datum::createDatum(InternalDataType type, void *data) { Datum result; result.d_as.d_type = type; result.d_as.d_ptr = data; return result; } inline Datum Datum::createDatum(InternalDataType type, int data) { Datum result; result.d_as.d_type = type; result.d_as.d_int64 = data; return result; } // PRIVATE ACCESSORS // 64-bit only inline void* Datum::theInlineStorage() { return d_data.buffer(); } inline const void* Datum::theInlineStorage() const { return d_data.buffer(); } #endif // BSLS_PLATFORM_CPU_32_BIT // This section contains all methods that are common for all platforms, but may // have platform-specific implementation. // PRIVATE CLASS METHODS inline void Datum::destroyMemory(const Datum& value, bslma::Allocator *basicAllocator) { #ifdef BSLS_PLATFORM_CPU_32_BIT basicAllocator->deallocate(const_cast<void*>(value.d_as.d_cvp)); #else // BSLS_PLATFORM_CPU_32_BIT basicAllocator->deallocate(value.d_as.d_ptr); #endif // BSLS_PLATFORM_CPU_32_BIT } // PRIVATE ACCESSORS inline Datum::InternalDataType Datum::internalType() const { #ifdef BSLS_PLATFORM_CPU_32_BIT if (0x7f == d_data[k_EXPONENT_MSB] && 0xf0 == (d_data[k_EXPONENT_LSB] & 0xf0)) { return static_cast<InternalDataType>(d_data[k_EXPONENT_LSB] & 0x0f); } return e_INTERNAL_DOUBLE; #else // BSLS_PLATFORM_CPU_32_BIT return static_cast<InternalDataType>(d_as.d_type); #endif // BSLS_PLATFORM_CPU_32_BIT } inline DatumArrayRef Datum::theArrayReference() const { #ifdef BSLS_PLATFORM_CPU_32_BIT return DatumArrayRef(static_cast<const Datum *>(d_as.d_cvp), d_as.d_ushort); #else // BSLS_PLATFORM_CPU_32_BIT return DatumArrayRef(static_cast<const Datum *>(d_as.d_ptr), d_as.d_int32); #endif // BSLS_PLATFORM_CPU_32_BIT } inline DatumArrayRef Datum::theInternalArray() const { #ifdef BSLS_PLATFORM_CPU_32_BIT const Datum *data = static_cast<const Datum *>(d_as.d_cvp); #else // BSLS_PLATFORM_CPU_32_BIT const Datum *data = reinterpret_cast<const Datum *>(d_as.d_ptr); #endif // BSLS_PLATFORM_CPU_32_BIT if (data) { const SizeType size = *reinterpret_cast<const SizeType *>(data); return DatumArrayRef(data + 1, size); // RETURN } return DatumArrayRef(0, 0); } inline bslstl::StringRef Datum::theInternalString() const { #ifdef BSLS_PLATFORM_CPU_32_BIT const char *data = static_cast<const char *>(d_as.d_cvp); return bslstl::StringRef(data + sizeof(SizeType), Datum_Helpers::load<SizeType>(data, 0)); #else // BSLS_PLATFORM_CPU_32_BIT return bslstl::StringRef(static_cast<const char *>(d_as.d_ptr), d_as.d_int32); #endif // BSLS_PLATFORM_CPU_32_BIT } BDLD_DATUM_FORCE_INLINE bslstl::StringRef Datum::theShortString() const { #ifdef BSLS_PLATFORM_CPU_32_BIT return bslstl::StringRef(d_string5.d_chars, d_string5.d_length); #else // BSLS_PLATFORM_CPU_32_BIT const char *str = reinterpret_cast<const char *>(theInlineStorage()); const SizeType len = *str++; return bslstl::StringRef(str, static_cast<int>(len)); #endif // BSLS_PLATFORM_CPU_32_BIT } inline bslstl::StringRef Datum::theStringReference() const { #ifdef BSLS_PLATFORM_CPU_32_BIT return bslstl::StringRef(static_cast<const char *>(d_as.d_cvp), d_as.d_ushort); #else // BSLS_PLATFORM_CPU_32_BIT return bslstl::StringRef(static_cast<const char *>(d_as.d_ptr), d_as.d_int32); #endif // BSLS_PLATFORM_CPU_32_BIT } // CLASS METHODS inline Datum Datum::createArrayReference(const Datum *array, SizeType length, bslma::Allocator *basicAllocator) { BSLS_ASSERT(array || 0 == length); BSLS_ASSERT(basicAllocator); #ifdef BSLS_PLATFORM_CPU_32_BIT // If the length will fit in the 'd_ushort' area, store everything inline; // otherwise, must allocate space. if (bsl::numeric_limits<unsigned short>::max() >= length) { Datum result; result.d_as.d_exponent = k_DOUBLE_MASK | e_INTERNAL_ARRAY_REFERENCE; result.d_as.d_ushort = static_cast<unsigned short>(length); result.d_as.d_cvp = array; return result; // RETURN } void *mem = basicAllocator->allocate(sizeof(array) + sizeof(length)); Datum_Helpers::store<const Datum *>(mem, 0, array); Datum_Helpers::store<SizeType> (mem, sizeof(array), length); return createExtendedDataObject(e_EXTENDED_INTERNAL_AREF_ALLOC, mem); #else // BSLS_PLATFORM_CPU_32_BIT (void)basicAllocator; BSLS_ASSERT(length <= bsl::numeric_limits<unsigned int>::max()); Datum result; result.d_as.d_type = e_INTERNAL_ARRAY_REFERENCE; result.d_as.d_int32 = static_cast<int>(length); result.d_as.d_ptr = reinterpret_cast<void*>(const_cast<Datum*>(array)); return result; #endif // BSLS_PLATFORM_CPU_32_BIT } inline Datum Datum::createArrayReference(const DatumArrayRef& value, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); return createArrayReference(value.data(), value.length(), basicAllocator); } inline Datum Datum::createBoolean(bool value) { Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT result.d_exp.d_value = (k_DOUBLE_MASK | e_INTERNAL_BOOLEAN) << k_TYPE_MASK_BITS; result.d_as.d_int = value; #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_BOOLEAN; result.d_as.d_int32 = value; #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createDate(const bdlt::Date& value) { Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT BSLMF_ASSERT(sizeof(value) == sizeof(result.d_as.d_int)); BSLMF_ASSERT(bsl::is_trivially_copyable<bdlt::Date>::value); result.d_exp.d_value = (k_DOUBLE_MASK | e_INTERNAL_DATE) << k_TYPE_MASK_BITS; *reinterpret_cast<bdlt::Date*>(&result.d_as.d_int) = value; #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_DATE; new (result.theInlineStorage()) bdlt::Date(value); #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createDatetime(const bdlt::Datetime& value, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); (void)basicAllocator; Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT // Check if number of days from now fits in two bytes. int dateOffsetFromEpoch = (value.date() - bdlt::EpochUtil::epoch().date()) - k_DATETIME_OFFSET_FROM_EPOCH; short shortDateOffsetFromEpoch = static_cast<short>(dateOffsetFromEpoch); if (static_cast<int>(shortDateOffsetFromEpoch) == dateOffsetFromEpoch && value.microsecond() == 0) { result.d_exp.d_value = (k_DOUBLE_MASK | e_INTERNAL_DATETIME) << k_TYPE_MASK_BITS | (0xffff & dateOffsetFromEpoch); bdlt::DatetimeInterval interval = value.time() - bdlt::Time(); result.d_as.d_int = static_cast<int>(interval.totalMilliseconds()); } else { void *mem = new (*basicAllocator) bdlt::Datetime(value); result = createExtendedDataObject(e_EXTENDED_INTERNAL_DATETIME_ALLOC, mem); } #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_DATETIME; new (result.theInlineStorage()) bdlt::Datetime(value); #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createDatetimeInterval( const bdlt::DatetimeInterval& value, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); (void)basicAllocator; Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT const int usValue = value.microseconds(); const bsls::Types::Int64 msValue = value.totalMilliseconds(); if (usValue == 0 && // Low-resolution (old) interval Datum_Helpers32::storeSmallInt64(msValue, &result.d_as.d_short, &result.d_as.d_int)) { result.d_as.d_exponent = k_DOUBLE_MASK | e_INTERNAL_DATETIME_INTERVAL; } else { void *mem = new (*basicAllocator) bdlt::DatetimeInterval(value); result = createExtendedDataObject( e_EXTENDED_INTERNAL_DATETIME_INTERVAL_ALLOC, mem); } #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_DATETIME_INTERVAL; result.d_as.d_int32 = value.days(); result.d_as.d_int64 = value.fractionalDayInMicroseconds(); #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createDouble(double value) { Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!(value == value))) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return createExtendedDataObject(e_EXTENDED_INTERNAL_NAN2, 0); // RETURN } else { result.d_double = value; } #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_DOUBLE; result.d_as.d_double = value; #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createError(int code) { #ifdef BSLS_PLATFORM_CPU_32_BIT return createExtendedDataObject(e_EXTENDED_INTERNAL_ERROR, code); #else // BSLS_PLATFORM_CPU_32_BIT return createDatum(e_INTERNAL_ERROR, code); #endif // BSLS_PLATFORM_CPU_32_BIT } inline Datum Datum::createInteger(int value) { Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT result.d_exp.d_value = (k_DOUBLE_MASK | e_INTERNAL_INTEGER) << k_TYPE_MASK_BITS; result.d_as.d_int = value; #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_INTEGER; result.d_as.d_int32 = value; #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createInteger64(bsls::Types::Int64 value, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT if (Datum_Helpers32::storeSmallInt64(value, &result.d_as.d_short, &result.d_as.d_int)) { result.d_as.d_exponent = k_DOUBLE_MASK | e_INTERNAL_INTEGER64; } else { void *mem = new (*basicAllocator) bsls::Types::Int64(value); result = createExtendedDataObject(e_EXTENDED_INTERNAL_INTEGER64_ALLOC, mem); } #else // BSLS_PLATFORM_CPU_32_BIT (void)basicAllocator; result.d_as.d_type = e_INTERNAL_INTEGER64; result.d_as.d_int64 = value; #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createNull() { Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT // Setting exponent using half-word is faster, maybe the compiler folds the // two statements into one? result.d_as.d_exponent = k_DOUBLE_MASK | Datum::e_INTERNAL_EXTENDED; result.d_as.d_ushort = e_EXTENDED_INTERNAL_NIL; #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_NIL; #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createStringRef(const char *string, SizeType length, bslma::Allocator *basicAllocator) { BSLS_ASSERT(string || 0 == length); BSLS_ASSERT(basicAllocator); #ifdef BSLS_PLATFORM_CPU_32_BIT // If the length will fit in the 'k_SHORT_OFFSET' area, store everything // inline; otherwise allocate space. if (bsl::numeric_limits<unsigned short>::max() >= length) { Datum result; result.d_exp.d_value = (k_DOUBLE_MASK | e_INTERNAL_STRING_REFERENCE) << k_TYPE_MASK_BITS | length; result.d_as.d_cvp = string; return result; // RETURN } void *mem = basicAllocator->allocate(sizeof(length) + sizeof(string)); Datum_Helpers::store<const char *>(mem, 0, string); Datum_Helpers::store<SizeType> (mem, sizeof(string), length); return createExtendedDataObject(e_EXTENDED_INTERNAL_SREF_ALLOC, mem); #else // BSLS_PLATFORM_CPU_32_BIT (void)basicAllocator; BSLS_ASSERT(length <= bsl::numeric_limits<unsigned int>::max()); Datum result; result.d_as.d_type = e_INTERNAL_STRING_REFERENCE; result.d_as.d_int32 = static_cast<int>(length); result.d_as.d_ptr = const_cast<char*>(string); return result; #endif // BSLS_PLATFORM_CPU_32_BIT } inline Datum Datum::createStringRef(const char *string, bslma::Allocator *basicAllocator) { BSLS_ASSERT(string); BSLS_ASSERT(basicAllocator); return createStringRef(string, bsl::strlen(string), basicAllocator); } inline Datum Datum::createStringRef(const bslstl::StringRef& value, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); return createStringRef(value.data(), value.length(), basicAllocator); } inline Datum Datum::createTime(const bdlt::Time& value) { Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT result.d_exp.d_value = (k_DOUBLE_MASK | e_INTERNAL_TIME) << k_TYPE_MASK_BITS; bsls::Types::Int64 rawTime; BSLMF_ASSERT(bsl::is_trivially_copyable<bdlt::Time>::value); *reinterpret_cast<bdlt::Time*>(&rawTime) = value; const bool rc = Datum_Helpers32::storeInt48(rawTime, &result.d_as.d_short, &result.d_as.d_int); BSLS_ASSERT(rc); (void)rc; #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_TIME; new (result.theInlineStorage()) bdlt::Time(value); #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::createUdt(void *data, int type) { BSLS_ASSERT(0 <= type && type <= 65535); Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT result.d_as.d_exponent = k_DOUBLE_MASK | e_INTERNAL_USERDEFINED; result.d_as.d_ushort = static_cast<unsigned short>(type); result.d_as.d_cvp = data; #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_USERDEFINED; result.d_as.d_int32 = type; result.d_as.d_ptr = data; #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::adoptArray(const DatumMutableArrayRef& array) { // Note that 'array.length' contains the *address* of the 'length' // information for the array, which precedes the 'array' data in a // contiguously allocated block (see 'DatumMutableArrayRef'). Datum result; #ifdef BSLS_PLATFORM_CPU_32_BIT result.d_as.d_exponent = k_DOUBLE_MASK | e_INTERNAL_ARRAY; result.d_as.d_cvp = array.length(); #else // BSLS_PLATFORM_CPU_32_BIT result.d_as.d_type = e_INTERNAL_ARRAY; result.d_as.d_ptr = array.length(); #endif // BSLS_PLATFORM_CPU_32_BIT return result; } inline Datum Datum::adoptMap(const DatumMutableMapRef& map) { // Note that 'map.size' contains the *address* of the 'size' information // for the map, which precedes the 'map' data in a contiguously allocated // block (see 'DatumMutableMapRef'). #ifdef BSLS_PLATFORM_CPU_32_BIT return createExtendedDataObject(e_EXTENDED_INTERNAL_MAP, map.size()); #else // BSLS_PLATFORM_CPU_32_BIT return createDatum(e_INTERNAL_MAP, map.size()); #endif // BSLS_PLATFORM_CPU_32_BIT } inline Datum Datum::adoptIntMap(const DatumMutableIntMapRef& map) { // Note that 'map.size' contains the *address* of the 'size' information // for the map, which precedes the 'map' data in a contiguously allocated // block (see 'DatumMutableIntMapRef'). #ifdef BSLS_PLATFORM_CPU_32_BIT return createExtendedDataObject(e_EXTENDED_INTERNAL_INT_MAP, map.size()); #else // BSLS_PLATFORM_CPU_32_BIT return createDatum(e_INTERNAL_INT_MAP, map.size()); #endif // BSLS_PLATFORM_CPU_32_BIT } inline Datum Datum::adoptMap(const DatumMutableMapOwningKeysRef& map) { // Note that 'map.size' contains the *address* of the 'size' information // for the map, which precedes the 'map' data in a contiguously allocated // block (see 'DatumMutableMapOwningKeysRefRef'). #ifdef BSLS_PLATFORM_CPU_32_BIT return createExtendedDataObject(e_EXTENDED_INTERNAL_OWNED_MAP, map.size()); #else // BSLS_PLATFORM_CPU_32_BIT return createDatum(e_INTERNAL_OWNED_MAP, map.size()); #endif // BSLS_PLATFORM_CPU_32_BIT } inline Datum Datum::copyString(const bslstl::StringRef& value, bslma::Allocator *basicAllocator) { return copyString(value.data(), value.length(), basicAllocator); } inline void Datum::disposeUninitializedArray( const DatumMutableArrayRef& array, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); basicAllocator->deallocate(array.length()); } inline void Datum::disposeUninitializedIntMap( const DatumMutableIntMapRef& map, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); basicAllocator->deallocate(map.size()); } inline void Datum::disposeUninitializedMap(const DatumMutableMapRef& map, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); basicAllocator->deallocate(map.size()); } inline void Datum::disposeUninitializedMap( const DatumMutableMapOwningKeysRef& map, bslma::Allocator *basicAllocator) { BSLS_ASSERT(basicAllocator); basicAllocator->deallocate(map.size()); } // ACCESSORS inline bool Datum::isArray() const { return (e_ARRAY == type()); } inline bool Datum::isBinary() const { return (e_BINARY == type()); } inline bool Datum::isBoolean() const { return (e_BOOLEAN == type()); } inline bool Datum::isDate() const { return (e_DATE == type()); } inline bool Datum::isDatetime() const { return (e_DATETIME == type()); } inline bool Datum::isDatetimeInterval() const { return (e_DATETIME_INTERVAL == type()); } inline bool Datum::isDecimal64() const { return (e_DECIMAL64 == type()); } inline bool Datum::isDouble() const { return (e_DOUBLE == type()); } inline bool Datum::isError() const { return (e_ERROR == type()); } inline bool Datum::isExternalReference() const { #ifdef BSLS_PLATFORM_CPU_32_BIT switch (internalType()) { case e_INTERNAL_STRING_REFERENCE: case e_INTERNAL_ARRAY_REFERENCE: case e_INTERNAL_USERDEFINED: return true; // RETURN case e_INTERNAL_EXTENDED: switch (extendedInternalType()) { case e_EXTENDED_INTERNAL_SREF_ALLOC: case e_EXTENDED_INTERNAL_AREF_ALLOC: return true; // RETURN default: break; } default: break; } #else // BSLS_PLATFORM_CPU_32_BIT switch (internalType()) { case e_INTERNAL_STRING_REFERENCE: case e_INTERNAL_ARRAY_REFERENCE: case e_INTERNAL_USERDEFINED: return true; // RETURN case e_INTERNAL_UNINITIALIZED: BSLS_ASSERT(!"Uninitialized Datum!!"); break; default: break; } #endif // BSLS_PLATFORM_CPU_32_BIT return false; } inline bool Datum::isInteger() const { return (e_INTEGER == type()); } inline bool Datum::isInteger64() const { return (e_INTEGER64 == type()); } inline bool Datum::isIntMap() const { return (e_INT_MAP == type()); } inline bool Datum::isMap() const { return (e_MAP == type()); } inline bool Datum::isNull() const { return (e_NIL == type()); } inline bool Datum::isString() const { return (e_STRING == type()); } inline bool Datum::isTime() const { return (e_TIME == type()); } inline bool Datum::isUdt() const { return (e_USERDEFINED == type()); } inline DatumArrayRef Datum::theArray() const { BSLS_ASSERT_SAFE(isArray()); const InternalDataType type = internalType(); if (e_INTERNAL_ARRAY == type) { return theInternalArray(); // RETURN } #ifdef BSLS_PLATFORM_CPU_32_BIT if (e_INTERNAL_EXTENDED == type) { return theLongArrayReference(); // RETURN } #endif // BSLS_PLATFORM_CPU_32_BIT return theArrayReference(); } inline DatumBinaryRef Datum::theBinary() const { BSLS_ASSERT_SAFE(isBinary()); #ifdef BSLS_PLATFORM_CPU_32_BIT return DatumBinaryRef(static_cast<const double *>(d_as.d_cvp) + 1,// RETURN *static_cast<const SizeType *>(d_as.d_cvp)); #else // BSLS_PLATFORM_CPU_32_BIT const InternalDataType type = internalType(); switch(type) { case e_INTERNAL_BINARY: return DatumBinaryRef(d_data.buffer(), // RETURN d_data.buffer()[k_SMALLBINARY_SIZE_OFFSET]); case e_INTERNAL_BINARY_ALLOC: return DatumBinaryRef(d_as.d_ptr, d_as.d_int32); // RETURN default: BSLS_ASSERT(!"NOT A BINARY"); } return DatumBinaryRef(); #endif // BSLS_PLATFORM_CPU_32_BIT } inline bool Datum::theBoolean() const { BSLS_ASSERT_SAFE(isBoolean()); #ifdef BSLS_PLATFORM_CPU_32_BIT return static_cast<bool>(d_as.d_int); #else // BSLS_PLATFORM_CPU_32_BIT return d_as.d_int32; #endif // BSLS_PLATFORM_CPU_32_BIT } inline bdlt::Date Datum::theDate() const { BSLS_ASSERT_SAFE(isDate()); #ifdef BSLS_PLATFORM_CPU_32_BIT return *reinterpret_cast<const bdlt::Date *>(&d_as.d_int); #else // BSLS_PLATFORM_CPU_32_BIT return *reinterpret_cast<const bdlt::Date *>(theInlineStorage()); #endif // BSLS_PLATFORM_CPU_32_BIT } inline bdlt::Datetime Datum::theDatetime() const { BSLS_ASSERT_SAFE(isDatetime()); #ifdef BSLS_PLATFORM_CPU_32_BIT const InternalDataType type = internalType(); if (type == e_INTERNAL_DATETIME) { bdlt::Time time; time.addMilliseconds(d_as.d_int); return bdlt::Datetime( bdlt::EpochUtil::epoch().date() + k_DATETIME_OFFSET_FROM_EPOCH + d_as.d_short, time); // RETURN } BSLS_ASSERT_SAFE(type == e_INTERNAL_EXTENDED); BSLS_ASSERT_SAFE( extendedInternalType() == e_EXTENDED_INTERNAL_DATETIME_ALLOC); return *static_cast<const bdlt::Datetime*>(d_as.d_cvp); #else // BSLS_PLATFORM_CPU_32_BIT return *reinterpret_cast<const bdlt::Datetime *>(theInlineStorage()); #endif // BSLS_PLATFORM_CPU_32_BIT } inline // BDLD_DATUM_FORCE_INLINE bdlt::DatetimeInterval Datum::theDatetimeInterval() const { BSLS_ASSERT_SAFE(isDatetimeInterval()); #ifdef BSLS_PLATFORM_CPU_32_BIT const InternalDataType type = internalType(); if (type == e_INTERNAL_DATETIME_INTERVAL) { bdlt::DatetimeInterval result; result.setTotalMilliseconds( Datum_Helpers32::loadSmallInt64(d_as.d_short, d_as.d_int)); return result; // RETURN } BSLS_ASSERT_SAFE(type == e_INTERNAL_EXTENDED); BSLS_ASSERT_SAFE( extendedInternalType() == e_EXTENDED_INTERNAL_DATETIME_INTERVAL_ALLOC); return *static_cast<const bdlt::DatetimeInterval *>(d_as.d_cvp); #else // BSLS_PLATFORM_CPU_32_BIT return bdlt::DatetimeInterval(d_as.d_int32, // days 0, // hours 0, // minutes 0, // seconds 0, // milliseconds d_as.d_int64); // microseconds #endif // BSLS_PLATFORM_CPU_32_BIT } #ifdef BSLS_PLATFORM_CPU_64_BIT inline bdldfp::Decimal64 Datum::theDecimal64() const { BSLS_ASSERT_SAFE(isDecimal64()); return *reinterpret_cast<const bdldfp::Decimal64 *>(theInlineStorage()); } #endif // BSLS_PLATFORM_CPU_64_BIT inline double Datum::theDouble() const { BSLS_ASSERT_SAFE(isDouble()); #ifdef BSLS_PLATFORM_CPU_32_BIT if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY( 0x7f != d_data[k_EXPONENT_MSB] || // exponent is not the 0xf0 != (d_data[k_EXPONENT_LSB] & 0xf0) || // special '7ff' value e_INTERNAL_INF == (d_data[k_EXPONENT_LSB] & 0x0f))) { // or infinity return d_double; // RETURN } BSLS_PERFORMANCEHINT_UNLIKELY_HINT; return bsl::numeric_limits<double>::quiet_NaN(); // RETURN #else // BSLS_PLATFORM_CPU_32_BIT return d_as.d_double; #endif // BSLS_PLATFORM_CPU_32_BIT } inline DatumError Datum::theError() const { BSLS_ASSERT(isError()); #ifdef BSLS_PLATFORM_CPU_32_BIT // If the extended type is 'e_EXTENDED_INTERNAL_ERROR', we are storing // just a code, at the data offset. Otherwise, we're storing an allocated // object. if (e_EXTENDED_INTERNAL_ERROR == extendedInternalType()) { return DatumError(d_as.d_int); // RETURN } const char *data = static_cast<const char *>(d_as.d_cvp); #else // BSLS_PLATFORM_CPU_32_BIT if (e_INTERNAL_ERROR == internalType()) { return DatumError(static_cast<int>(d_as.d_int64)); // RETURN } const char *data = reinterpret_cast<const char*>(d_as.d_ptr); #endif // BSLS_PLATFORM_CPU_32_BIT return DatumError( Datum_Helpers::load<int>(data, 0), bslstl::StringRef(data + 2 * sizeof(int), Datum_Helpers::load<int>(data, sizeof(int)))); } inline int Datum::theInteger() const { BSLS_ASSERT_SAFE(isInteger()); #ifdef BSLS_PLATFORM_CPU_32_BIT return d_as.d_int; #else // BSLS_PLATFORM_CPU_32_BIT return d_as.d_int32; #endif // BSLS_PLATFORM_CPU_32_BIT } inline bsls::Types::Int64 Datum::theInteger64() const { BSLS_ASSERT_SAFE(isInteger64()); #ifdef BSLS_PLATFORM_CPU_32_BIT const InternalDataType type = internalType(); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(e_INTERNAL_INTEGER64 == type)) { return theSmallInteger64(); // RETURN } BSLS_ASSERT_SAFE(e_INTERNAL_EXTENDED == type); BSLS_ASSERT_SAFE( e_EXTENDED_INTERNAL_INTEGER64_ALLOC == extendedInternalType()); return theLargeInteger64(); // RETURN #else // BSLS_PLATFORM_CPU_32_BIT return d_as.d_int64; #endif // BSLS_PLATFORM_CPU_32_BIT } inline DatumMapRef Datum::theMap() const { BSLS_ASSERT_SAFE(isMap()); #ifdef BSLS_PLATFORM_CPU_32_BIT const DatumMapEntry *map = static_cast<const DatumMapEntry *>(d_as.d_cvp); #else // BSLS_PLATFORM_CPU_32_BIT const DatumMapEntry *map = static_cast<const DatumMapEntry *>(d_as.d_ptr); #endif // BSLS_PLATFORM_CPU_32_BIT if (map) { // Map header takes first DatumMapEntry const Datum_MapHeader *header = reinterpret_cast<const Datum_MapHeader *>(map); return DatumMapRef(map + 1, header->d_size, header->d_sorted, header->d_ownsKeys); // RETURN } return DatumMapRef(0, 0, false, false); } inline DatumIntMapRef Datum::theIntMap() const { BSLS_ASSERT_SAFE(isIntMap()); #ifdef BSLS_PLATFORM_CPU_32_BIT const DatumIntMapEntry *map = static_cast<const DatumIntMapEntry *>(d_as.d_cvp); #else // BSLS_PLATFORM_CPU_32_BIT const DatumIntMapEntry *map = static_cast<const DatumIntMapEntry *>(d_as.d_ptr); #endif // BSLS_PLATFORM_CPU_32_BIT if (map) { // Map header takes first DatumMapEntry const Datum_IntMapHeader *header = reinterpret_cast<const Datum_IntMapHeader *>(map); return DatumIntMapRef(map + 1, header->d_size, header->d_sorted); // RETURN } return DatumIntMapRef(0, 0, false); } inline bslstl::StringRef Datum::theString() const { BSLS_ASSERT_SAFE(isString()); const InternalDataType type = internalType(); switch(type) { case e_INTERNAL_SHORTSTRING: return theShortString(); // RETURN case e_INTERNAL_STRING: return theInternalString(); // RETURN case e_INTERNAL_STRING_REFERENCE: return theStringReference(); // RETURN #ifdef BSLS_PLATFORM_CPU_32_BIT case e_INTERNAL_LONGEST_SHORTSTRING: return theLongestShortString(); // RETURN default: return theLongStringReference(); // RETURN #else // BSLS_PLATFORM_CPU_32_BIT default: { BSLS_ASSERT(false); return bslstl::StringRef(); // RETURN } #endif // BSLS_PLATFORM_CPU_32_BIT } } inline bdlt::Time Datum::theTime() const { BSLS_ASSERT_SAFE(isTime()); #ifdef BSLS_PLATFORM_CPU_32_BIT BSLMF_ASSERT(bsl::is_trivially_copyable<bdlt::Time>::value); bsls::Types::Int64 rawTime; rawTime = Datum_Helpers32::loadInt48(d_as.d_short, d_as.d_int); return *reinterpret_cast<bdlt::Time*>(&rawTime); #else // BSLS_PLATFORM_CPU_32_BIT return *reinterpret_cast<const bdlt::Time *>(theInlineStorage()); #endif // BSLS_PLATFORM_CPU_32_BIT } inline DatumUdt Datum::theUdt() const { BSLS_ASSERT_SAFE(isUdt()); #ifdef BSLS_PLATFORM_CPU_32_BIT return DatumUdt(const_cast<void*>(d_as.d_cvp), d_as.d_ushort); #else // BSLS_PLATFORM_CPU_32_BIT return DatumUdt(d_as.d_ptr, d_as.d_int32); #endif // BSLS_PLATFORM_CPU_32_BIT } inline Datum::DataType Datum::type() const { #ifdef BSLS_PLATFORM_CPU_32_BIT static const DataType convert[] = { e_DOUBLE // e_INTERNAL_INF = 0x00 , e_STRING // e_INTERNAL_LONGEST_SHORTSTR = 0x01 , e_BOOLEAN // e_INTERNAL_BOOLEAN = 0x02 , e_STRING // e_INTERNAL_SHORTSTRING = 0x03 , e_STRING // e_INTERNAL_STRING = 0x04 , e_DATE // e_INTERNAL_DATE = 0x05 , e_TIME // e_INTERNAL_TIME = 0x06 , e_DATETIME // e_INTERNAL_DATETIME = 0x07 , e_DATETIME_INTERVAL // e_INTERNAL_DATETIME_INTERVAL = 0x08 , e_INTEGER // e_INTERNAL_INTEGER = 0x09 , e_INTEGER64 // e_INTERNAL_INTEGER64 = 0x0a , e_USERDEFINED // e_INTERNAL_USERDEFINED = 0x0b , e_ARRAY // e_INTERNAL_ARRAY = 0x0c , e_STRING // e_INTERNAL_STRING_REFERENCE = 0x0d , e_ARRAY // e_INTERNAL_ARRAY_REFERENCE = 0x0e , e_NIL // e_INTERNAL_EXTENDED = 0x0f , e_DOUBLE // e_INTERNAL_DOUBLE = 0x10 }; const InternalDataType type = internalType(); if (e_INTERNAL_EXTENDED == type) { return typeFromExtendedInternalType(); // RETURN } return convert[type]; #else // BSLS_PLATFORM_CPU_32_BIT static const DataType convert[] = { e_ERROR // e_INTERNAL_UNINITIALIZED; invalid , e_DOUBLE // e_INTERNAL_INF = 1 , e_NIL // e_INTERNAL_NIL = 2 , e_BOOLEAN // e_INTERNAL_BOOLEAN = 3 , e_STRING // e_INTERNAL_SHORTSTRING = 4 , e_STRING // e_INTERNAL_STRING = 5 , e_DATE // e_INTERNAL_DATE = 6 , e_TIME // e_INTERNAL_TIME = 7 , e_DATETIME // e_INTERNAL_DATETIME = 8 , e_DATETIME_INTERVAL // e_INTERNAL_DATETIME_INTERVAL = 9 , e_INTEGER // e_INTERNAL_INTEGER = 10 , e_INTEGER64 // e_INTERNAL_INTEGER64 = 11 , e_USERDEFINED // e_INTERNAL_USERDEFINED = 12 , e_ARRAY // e_INTERNAL_ARRAY = 13 , e_STRING // e_INTERNAL_STRING_REFERENCE = 14 , e_ARRAY // e_INTERNAL_ARRAY_REFERENCE = 15 , e_DOUBLE // e_INTERNAL_DOUBLE = 16 , e_MAP // e_INTERNAL_MAP = 17 , e_MAP // e_INTERNAL_OWNED_MAP = 18 , e_ERROR // e_INTERNAL_ERROR = 19 , e_ERROR // e_INTERNAL_ERROR_ALLOC = 20 , e_BINARY // e_INTERNAL_BINARY = 21 , e_BINARY // e_INTERNAL_BINARY_ALLOC = 22 , e_DECIMAL64 // e_INTERNAL_DECIMAL64 = 23 , e_INT_MAP // e_INTERNAL_INT_MAP = 24 }; const InternalDataType type = internalType(); BSLS_ASSERT_SAFE(e_INTERNAL_UNINITIALIZED != type); return convert[type]; #endif // BSLS_PLATFORM_CPU_32_BIT } #ifdef BSLS_PLATFORM_CPU_32_BIT template <class BDLD_VISITOR> void Datum::apply(BDLD_VISITOR& visitor) const { switch (internalType()) { case e_INTERNAL_INF: visitor(bsl::numeric_limits<double>::infinity()); break; case e_INTERNAL_BOOLEAN: visitor(theBoolean()); break; case e_INTERNAL_SHORTSTRING: visitor(theShortString()); break; case e_INTERNAL_LONGEST_SHORTSTRING: visitor(theLongestShortString()); break; case e_INTERNAL_STRING: visitor(theInternalString()); break; case e_INTERNAL_DATE: visitor(theDate()); break; case e_INTERNAL_TIME: visitor(theTime()); break; case e_INTERNAL_DATETIME: visitor(theDatetime()); break; case e_INTERNAL_DATETIME_INTERVAL: visitor(theDatetimeInterval()); break; case e_INTERNAL_INTEGER: visitor(theInteger()); break; case e_INTERNAL_INTEGER64: visitor(theInteger64()); break; case e_INTERNAL_USERDEFINED: visitor(theUdt()); break; case e_INTERNAL_ARRAY: visitor(theInternalArray()); break; case e_INTERNAL_STRING_REFERENCE: visitor(theStringReference()); break; case e_INTERNAL_ARRAY_REFERENCE: visitor(theArrayReference()); break; case e_INTERNAL_EXTENDED: switch (extendedInternalType()) { case e_EXTENDED_INTERNAL_INT_MAP: visitor(theIntMap()); break; case e_EXTENDED_INTERNAL_MAP: BSLS_ANNOTATION_FALLTHROUGH; case e_EXTENDED_INTERNAL_OWNED_MAP: visitor(theMap()); break; case e_EXTENDED_INTERNAL_NAN2: visitor(theDouble()); break; case e_EXTENDED_INTERNAL_ERROR: BSLS_ANNOTATION_FALLTHROUGH; case e_EXTENDED_INTERNAL_ERROR_ALLOC: visitor(theError()); break; case e_EXTENDED_INTERNAL_SREF_ALLOC: visitor(theLongStringReference()); break; case e_EXTENDED_INTERNAL_AREF_ALLOC: visitor(theLongArrayReference()); break; case e_EXTENDED_INTERNAL_DATETIME_ALLOC: visitor(theDatetime()); break; case e_EXTENDED_INTERNAL_DATETIME_INTERVAL_ALLOC: visitor(theDatetimeInterval()); break; case e_EXTENDED_INTERNAL_INTEGER64_ALLOC: visitor(theInteger64()); break; case e_EXTENDED_INTERNAL_BINARY_ALLOC: visitor(theBinary()); break; case e_EXTENDED_INTERNAL_DECIMAL64: case e_EXTENDED_INTERNAL_DECIMAL64_SPECIAL: case e_EXTENDED_INTERNAL_DECIMAL64_ALLOC: visitor(theDecimal64()); break; case e_EXTENDED_INTERNAL_NIL: visitor(bslmf::Nil()); break; default: BSLS_ASSERT_SAFE(!"UNKNOWN TYPE"); } break; case e_INTERNAL_DOUBLE: visitor(d_double); break; default: BSLS_ASSERT_SAFE(!"Unknown type!!"); } } #else // BSLS_PLATFORM_CPU_32_BIT template <class BDLD_VISITOR> void Datum::apply(BDLD_VISITOR& visitor) const { switch (internalType()) { case e_INTERNAL_INF: visitor(bsl::numeric_limits<double>::infinity()); break; case e_INTERNAL_NIL: visitor(bslmf::Nil()); break; case e_INTERNAL_BOOLEAN: visitor(theBoolean()); break; case e_INTERNAL_SHORTSTRING: visitor(theShortString()); break; case e_INTERNAL_STRING: visitor(theInternalString()); break; case e_INTERNAL_DATE: visitor(theDate()); break; case e_INTERNAL_TIME: visitor(theTime()); break; case e_INTERNAL_DATETIME: visitor(theDatetime()); break; case e_INTERNAL_DATETIME_INTERVAL: visitor(theDatetimeInterval()); break; case e_INTERNAL_INTEGER: visitor(theInteger()); break; case e_INTERNAL_INTEGER64: visitor(theInteger64()); break; case e_INTERNAL_USERDEFINED: visitor(theUdt()); break; case e_INTERNAL_ARRAY: visitor(theInternalArray()); break; case e_INTERNAL_STRING_REFERENCE: visitor(theStringReference()); break; case e_INTERNAL_ARRAY_REFERENCE: visitor(theArrayReference()); break; case e_INTERNAL_MAP: BSLS_ANNOTATION_FALLTHROUGH; case e_INTERNAL_OWNED_MAP: visitor(theMap()); break; case e_INTERNAL_ERROR: BSLS_ANNOTATION_FALLTHROUGH; case e_INTERNAL_ERROR_ALLOC: visitor(theError()); break; case e_INTERNAL_DOUBLE: visitor(d_as.d_double); break; case e_INTERNAL_BINARY: BSLS_ANNOTATION_FALLTHROUGH; case e_INTERNAL_BINARY_ALLOC: visitor(theBinary()); break; case e_INTERNAL_DECIMAL64: visitor(theDecimal64()); break; case e_INTERNAL_INT_MAP: visitor(theIntMap()); break; case e_INTERNAL_UNINITIALIZED: BSLS_ASSERT(!"Uninitialized Datum!!"); break; default: BSLS_ASSERT_SAFE(!"Unknown type!!"); } } #endif // BSLS_PLATFORM_CPU_32_BIT #ifndef BDE_OMIT_INTERNAL_DEPRECATED inline void Datum::createUninitializedMapOwningKeys( DatumMutableMapOwningKeysRef *result, SizeType capacity, SizeType keysCapacity, bslma::Allocator *basicAllocator) { createUninitializedMap(result, capacity, keysCapacity, basicAllocator); } inline Datum Datum::adoptMapOwningKeys(const DatumMutableMapOwningKeysRef& mapping) { return adoptMap(mapping); } inline void Datum::disposeUninitializedMapOwningKeys( const DatumMutableMapOwningKeysRef& mapping, bslma::Allocator *basicAllocator) { return disposeUninitializedMap(mapping, basicAllocator); } #endif // ------------------- // class DatumArrayRef // ------------------- // CREATORS inline DatumArrayRef::DatumArrayRef() : d_data_p(0) , d_length(0) { } inline DatumArrayRef::DatumArrayRef(const Datum *data, SizeType length) : d_data_p(data) , d_length(length) { BSLS_ASSERT(data || 0 == length); } // ACCESSORS inline const Datum& DatumArrayRef::operator[](SizeType index) const { BSLS_ASSERT_SAFE(index < d_length); return d_data_p[index]; } inline const Datum *DatumArrayRef::data() const { return d_data_p; } inline DatumArrayRef::SizeType DatumArrayRef::length() const { return d_length; } // ---------------------- // class DatumIntMapEntry // ---------------------- // CREATORS inline DatumIntMapEntry::DatumIntMapEntry() { } inline DatumIntMapEntry::DatumIntMapEntry(int key, const Datum& value) : d_key(key) , d_value(value) { } // MANIPULATORS inline void DatumIntMapEntry::setKey(int key) { d_key = key; } inline void DatumIntMapEntry::setValue(const Datum& value) { d_value = value; } // ACCESSORS inline int DatumIntMapEntry::key() const { return d_key; } inline const Datum& DatumIntMapEntry::value() const { return d_value; } // -------------------- // class DatumIntMapRef // -------------------- // CREATORS inline DatumIntMapRef::DatumIntMapRef(const DatumIntMapEntry *data, SizeType size, bool sorted) : d_data_p(data) , d_size(size) , d_sorted(sorted) { BSLS_ASSERT((size && data) || !size); } // ACCESSORS inline const DatumIntMapEntry& DatumIntMapRef::operator[](SizeType index) const { BSLS_ASSERT_SAFE(index < d_size); return d_data_p[index]; } inline const DatumIntMapEntry *DatumIntMapRef::data() const { return d_data_p; } inline bool DatumIntMapRef::isSorted() const { return d_sorted; } inline DatumIntMapRef::SizeType DatumIntMapRef::size() const { return d_size; } // ------------------- // class DatumMapEntry // ------------------- // CREATORS inline DatumMapEntry::DatumMapEntry() { } inline DatumMapEntry::DatumMapEntry(const bslstl::StringRef& key, const Datum& value) : d_key_p(key) , d_value(value) { } // MANIPULATORS inline void DatumMapEntry::setKey(const bslstl::StringRef& key) { d_key_p = key; } inline void DatumMapEntry::setValue(const Datum& value) { d_value = value; } // ACCESSORS inline const bslstl::StringRef& DatumMapEntry::key() const { return d_key_p; } inline const Datum& DatumMapEntry::value() const { return d_value; } // ----------------- // class DatumMapRef // ----------------- // CREATORS inline DatumMapRef::DatumMapRef(const DatumMapEntry *data, SizeType size, bool sorted, bool ownsKeys) : d_data_p(data) , d_size(size) , d_sorted(sorted) , d_ownsKeys(ownsKeys) { BSLS_ASSERT((size && data) || !size); if (0 == size) { d_ownsKeys = false; } } // ACCESSORS inline const DatumMapEntry& DatumMapRef::operator[](SizeType index) const { BSLS_ASSERT_SAFE(index < d_size); return d_data_p[index]; } inline const DatumMapEntry *DatumMapRef::data() const { return d_data_p; } inline bool DatumMapRef::isSorted() const { return d_sorted; } inline bool DatumMapRef::ownsKeys() const { return d_ownsKeys; } inline DatumMapRef::SizeType DatumMapRef::size() const { return d_size; } // -------------------------- // class DatumMutableArrayRef // -------------------------- // CREATORS inline DatumMutableArrayRef::DatumMutableArrayRef() : d_data_p(0) , d_length_p(0) { } inline DatumMutableArrayRef::DatumMutableArrayRef(Datum *data, SizeType *length) : d_data_p(data) , d_length_p(length) { } // ACCESSORS inline Datum *DatumMutableArrayRef::data() const { return d_data_p; } inline DatumMutableArrayRef::SizeType *DatumMutableArrayRef::length() const { return d_length_p; } // --------------------------- // class DatumMutableIntMapRef // --------------------------- // CREATORS inline DatumMutableIntMapRef::DatumMutableIntMapRef() : d_data_p(0) , d_size_p(0) , d_sorted_p(0) { } inline DatumMutableIntMapRef::DatumMutableIntMapRef(DatumIntMapEntry *data, SizeType *size, bool *sorted) : d_data_p(data) , d_size_p(size) , d_sorted_p(sorted) { } // ACCESSORS inline DatumIntMapEntry *DatumMutableIntMapRef::data() const { return d_data_p; } inline DatumMutableIntMapRef::SizeType *DatumMutableIntMapRef::size() const { return d_size_p; } inline bool *DatumMutableIntMapRef::sorted() const { return d_sorted_p; } // ------------------------ // class DatumMutableMapRef // ------------------------ // CREATORS inline DatumMutableMapRef::DatumMutableMapRef() : d_data_p(0) , d_size_p(0) , d_sorted_p(0) { } inline DatumMutableMapRef::DatumMutableMapRef(DatumMapEntry *data, SizeType *size, bool *sorted) : d_data_p(data) , d_size_p(size) , d_sorted_p(sorted) { } // ACCESSORS inline DatumMapEntry *DatumMutableMapRef::data() const { return d_data_p; } inline DatumMutableMapRef::SizeType *DatumMutableMapRef::size() const { return d_size_p; } inline bool *DatumMutableMapRef::sorted() const { return d_sorted_p; } // ---------------------------------- // class DatumMutableMapOwningKeysRef // ---------------------------------- // CREATORS inline DatumMutableMapOwningKeysRef::DatumMutableMapOwningKeysRef() : d_data_p(0) , d_size_p(0) , d_keys_p(0) , d_sorted_p(0) { } inline DatumMutableMapOwningKeysRef::DatumMutableMapOwningKeysRef( DatumMapEntry *data, SizeType *size, char *keys, bool *sorted) : d_data_p(data) , d_size_p(size) , d_keys_p(keys) , d_sorted_p(sorted) { } // ACCESSORS inline DatumMapEntry *DatumMutableMapOwningKeysRef::data() const { return d_data_p; } inline char *DatumMutableMapOwningKeysRef::keys() const { return d_keys_p; } inline DatumMutableMapOwningKeysRef::SizeType * DatumMutableMapOwningKeysRef::size() const { return d_size_p; } inline bool *DatumMutableMapOwningKeysRef::sorted() const { return d_sorted_p; } } // close package namespace // FREE OPERATORS inline bool bdld::operator!=(const Datum& lhs, const Datum& rhs) { return !(lhs == rhs); } inline bool bdld::operator!=(const DatumArrayRef& lhs, const DatumArrayRef& rhs) { return !(lhs == rhs); } inline bool bdld::operator==(const DatumIntMapEntry& lhs, const DatumIntMapEntry& rhs) { return (lhs.key() == rhs.key()) && (lhs.value() == rhs.value()); } inline bool bdld::operator!=(const DatumIntMapEntry& lhs, const DatumIntMapEntry& rhs) { return !(lhs == rhs); } inline bool bdld::operator!=(const DatumIntMapRef& lhs, const DatumIntMapRef& rhs) { return !(lhs == rhs); } inline bool bdld::operator==(const DatumMapEntry& lhs, const DatumMapEntry& rhs) { return (lhs.key() == rhs.key()) && (lhs.value() == rhs.value()); } inline bool bdld::operator!=(const DatumMapEntry& lhs, const DatumMapEntry& rhs) { return !(lhs == rhs); } inline bool bdld::operator!=(const DatumMapRef& lhs, const DatumMapRef& rhs) { return !(lhs == rhs); } inline bsl::ostream& bdld::operator<<(bsl::ostream& stream, const Datum& rhs) { return rhs.print(stream, 0, -1); } template <class HASH_ALGORITHM> void bdld::hashAppend(HASH_ALGORITHM& hashAlg, const bdld::Datum& input) { using bslh::hashAppend; hashAppend(hashAlg, input.type()); switch (input.type()) { case bdld::Datum::e_NIL: { // Do nothing. This is sufficient because 'type' has already been // hashed (differentiating the nil value). } break; case bdld::Datum::e_INTEGER: { hashAppend(hashAlg, input.theInteger()); } break; case bdld::Datum::e_DOUBLE: { hashAppend(hashAlg, input.theDouble()); } break; case bdld::Datum::e_STRING: { hashAppend(hashAlg, input.theString()); } break; case bdld::Datum::e_BOOLEAN: { hashAppend(hashAlg, input.theBoolean()); } break; case bdld::Datum::e_ERROR: { hashAppend(hashAlg, input.theError().code()); hashAppend(hashAlg, input.theError().message()); } break; case bdld::Datum::e_DATE: { hashAppend(hashAlg, input.theDate()); } break; case bdld::Datum::e_TIME: { hashAppend(hashAlg, input.theTime()); } break; case bdld::Datum::e_DATETIME: { hashAppend(hashAlg, input.theDatetime()); } break; case bdld::Datum::e_DATETIME_INTERVAL: { hashAppend(hashAlg, input.theDatetimeInterval()); } break; case bdld::Datum::e_INTEGER64: { hashAppend(hashAlg, input.theInteger64()); } break; case bdld::Datum::e_USERDEFINED: { hashAppend(hashAlg, input.theUdt().type()); hashAppend(hashAlg, input.theUdt().data()); } break; case bdld::Datum::e_ARRAY: { hashAppend(hashAlg, input.theArray().length()); for (bsl::size_t i = 0; i < input.theArray().length(); ++i) { bdld::hashAppend(hashAlg, input.theArray()[i]); } } break; case bdld::Datum::e_MAP: { hashAppend(hashAlg, input.theMap().size()); for (bsl::size_t i = 0; i < input.theMap().size(); ++i) { hashAppend(hashAlg, input.theMap()[i].key()); bdld::hashAppend(hashAlg, input.theMap()[i].value()); } } break; case bdld::Datum::e_BINARY: { hashAppend(hashAlg, input.theBinary().size()); if (input.theBinary().size() > 0) { hashAlg(input.theBinary().data(), input.theBinary().size()); } } break; case bdld::Datum::e_DECIMAL64: { hashAppend(hashAlg, input.theDecimal64()); } break; case bdld::Datum::e_INT_MAP: { hashAppend(hashAlg, input.theIntMap().size()); for (bsl::size_t i = 0; i < input.theIntMap().size(); ++i) { hashAppend(hashAlg, input.theIntMap()[i].key()); bdld::hashAppend(hashAlg, input.theIntMap()[i].value()); } } break; default: { BSLS_ASSERT(!"unknown 'bdld::Datum' type"); } } } inline bsl::ostream& bdld::operator<<(bsl::ostream& stream, const DatumArrayRef& rhs) { return rhs.print(stream, 0 , -1); } inline bsl::ostream& bdld::operator<<(bsl::ostream& stream, const DatumMapEntry& rhs) { return rhs.print(stream, 0 , -1); } inline bsl::ostream& bdld::operator<<(bsl::ostream& stream, const DatumIntMapEntry& rhs) { return rhs.print(stream, 0 , -1); } inline bsl::ostream& bdld::operator<<(bsl::ostream& stream, const DatumIntMapRef& rhs) { return rhs.print(stream, 0 , -1); } inline bsl::ostream& bdld::operator<<(bsl::ostream& stream, const DatumMapRef& rhs) { return rhs.print(stream, 0 , -1); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2020 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------