// bdld_datumarraybuilder.h -*-C++-*- #ifndef INCLUDED_BDLD_DATUMARRAYBUILDER #define INCLUDED_BDLD_DATUMARRAYBUILDER #include <bsls_ident.h> BSLS_IDENT("$Id$ $CSID$") //@PURPOSE: Provide a utility to build a 'Datum' object holding an array. // //@CLASSES: // bdld::DatumArrayBuilder: utility to build a 'Datum' object holding an array // //@SEE_ALSO: bdld_datum // //@DESCRIPTION: This component defines a mechanism, 'bdld::DatumArrayBuilder', // used to populate a 'Datum' array value in an exception-safe manner. In // addition to providing exception safety, a 'DatumArrayBuilder' is // particularly useful when the length of the array to be constructed is not // known in advance. The user can append elements to the datum array as // needed, and when there are no more elements to append the user calls // 'commit' and ownership of the populated 'Datum' object is transferred to the // caller. After the call to 'commit', no additional elements can be appended // to the 'Datum' array value. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Using a 'DatumArrayBuilder' to Create a 'Datum' array. ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Suppose we receive a string that is constructed by streaming a bunch of // values together in the format shown below: //.. // "2.34,4,hi there,true" //.. // Notice that the values are separated by a ','. Also note that a ',' is not // allowed to be part of a string value to simplify the implementation of the // utility that parses this string. The following code snippets illustrate how // to create a 'Datum' object that holds an array of 'Datum' objects // constructed using the streamed values. // // First we define a function 'nextValue' that we will use to tokenize the // input string: //.. // bsl::size_t nextValue(bsl::string *value, const bsl::string& input) // // Extract the next value from a list of comma separated values in the // // specified 'input' string and load it in the specified 'value'. // // Return the index of the next value within 'input'. // { // if (input.empty()) { // return bsl::string::npos; // } // int start = 0; // bsl::size_t nextIndex = input.find(',', start); // if (bsl::string::npos != nextIndex) { // *value = input.substr(start, nextIndex - start); // } // else { // *value = input.substr(start); // } // return nextIndex; // } //.. // Next, we define a function 'convertToDatum' that will convert a string // token into a 'Datum' scalar value: //.. // bdld::Datum convertToDatum(const bsl::string& token, // bslma::Allocator *basicAllocator) // // Convert the specified 'token' into the appropriate type of scalar // // value and then create and return a 'Datum' object using that value. // // Use the specified 'basicAllocator' to supply memory. // { // bool isInteger = true; // bool isDouble = false; // bool isBoolean = false; // for (bsl::size_t i = 0; i < token.size(); ++i) { // if (!isdigit(token[i])) { // if ('.' == token[i] && !isDouble) { // isDouble = true; // isInteger = false; // continue; // } // isInteger = false; // isDouble = false; // break; // } // } // // if (!isInteger && !isDouble) { // if ("true" == token || "false" == token) { // isBoolean = true; // } // } // // if (isInteger) { // integer token // return bdld::Datum::createInteger(atoi(token.c_str())); // } // else if (isDouble) { // double token // return bdld::Datum::createDouble(atof(token.c_str())); // } // else if (isBoolean) { // boolean token // return bdld::Datum::createBoolean("true" == token ? true : false); // } // else { // string value // return bdld::Datum::copyString(token, basicAllocator); // } // } //.. // Now, in our example main, we tokenize an input string "2.34,4,hi there,true" // to populate a 'Datum' array containing the values '[2.34, 4, "hi there", // true]': //.. // void exampleMain() { // bslma::TestAllocator allocator; // const bsl::string input("2.34,4,hi there,true", &allocator); //.. // Here, we create a 'DatumArrayBuilder', and iterate over the parsed tokens // from 'input', using 'pushBack' on the array builder to add the tokens to a // 'Datum' array value: //.. // bdld::DatumArrayBuilder builder(0, &allocator); // // bsl::string str(input, &allocator); // // bsl::string value; // bsl::size_t nextIndex; // do { // nextIndex = nextValue(&value, str); // builder.pushBack(convertToDatum(value, &allocator)); // if (bsl::string::npos == nextIndex) { // break; // } // str = str.substr(nextIndex + 1); // } while (bsl::string::npos != nextIndex); // // bdld::Datum result = builder.commit(); //.. // Notice that calling 'commit' on the 'DatumArrayBuilder' adopts ownership // for the returned 'Datum' object, and that the behavior is undefined if // 'pushBack' is called after 'commit'. // // Finally, we verify that 'result' has the expected array value, and destroy // the created 'Datum' value: //.. // assert(true == result.isArray()); // assert(4 == result.theArray().length()); // assert(true == result.theArray()[0].isDouble()); // assert(2.34 == result.theArray()[0].theDouble()); // assert(true == result.theArray()[1].isInteger()); // assert(4 == result.theArray()[1].theInteger()); // assert(true == result.theArray()[2].isString()); // assert("hi there" == result.theArray()[2].theString()); // assert(true == result.theArray()[3].isBoolean()); // assert(true == result.theArray()[3].theBoolean()); // // // Destroy the 'Datum' object. // bdld::Datum::destroy(result, &allocator); // } //.. #include <bdlscm_version.h> #include <bdld_datum.h> #include <bslma_stdallocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_nestedtraitdeclaration.h> #include <bsls_types.h> namespace BloombergLP { namespace bdld { // ======================= // class DatumArrayBuilder // ======================= class DatumArrayBuilder { // This 'class' provides a mechanism to build a 'Datum' object having an // array value in an exception-safe manner. public: // TYPES typedef bsls::Types::size_type SizeType; // 'SizeType' is an alias for an unsigned integral value, representing // the capacity or length of a datum array. typedef bsl::allocator<char> allocator_type; private: // DATA DatumMutableArrayRef d_array; // mutable access to the datum array SizeType d_capacity; // capacity of the datum array allocator_type d_allocator; // allocator for memory private: // NOT IMPLEMENTED DatumArrayBuilder(const DatumArrayBuilder&); DatumArrayBuilder& operator=(const DatumArrayBuilder&); public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(DatumArrayBuilder, bslma::UsesBslmaAllocator); // 'DatumArrayBuilder' is allocator-aware. // CREATORS DatumArrayBuilder(); explicit DatumArrayBuilder(const allocator_type& allocator); explicit DatumArrayBuilder( SizeType initialCapacity, const allocator_type& allocator = allocator_type()); // Create a 'DatumArrayBuilder' object that will administer the process // of building a 'Datum' array. Optionally specify an // 'initialCapacity' for the array. If 'initialCapacity' is not // supplied, the initial capacity of the array is 0. Optionally // specify an 'allocator' (e.g., the address of a 'bslma::Allocator' // object) to supply memory; otherwise, the default allocator is used. ~DatumArrayBuilder(); // Destroy this object. If this object is holding a 'Datum' array that // has not been adopted, then the 'Datum' array is disposed after // destroying each of its elements. // MANIPULATORS void append(const Datum *values, SizeType length); // Append the specified array 'values' having the specified 'length' to // the 'Datum' array being built by this object. The behavior is // undefined unless '0 != length && 0 != values' and each element in // 'values' that needs dynamic memory, is allocated with the same // allocator that was used to construct this object. The behavior is // also undefined if 'commit' has already been called on this object. Datum commit(); // Return a 'Datum' array value holding the elements supplied to // 'pushBack' or 'append'. The caller is responsible for releasing the // resources of the returned 'Datum' object. Calling this method // indicates that the caller is finished building the datum array and // no further values shall be appended. It is undefined behavior to // call any method of this object, other than the destructor, after // 'commit' has been called. void pushBack(const Datum& value); // Append the specified 'value' to the 'Datum' array being built by // this object. The behavior is undefined if 'value' needs dynamic // memory and was allocated using a different allocator than the one // used to construct this object. The behavior is also undefined if // 'commit' has already been called on this object. // ACCESSORS SizeType capacity() const; // Return the capacity of the held 'Datum' array. The behavior is // undefined if 'commit' has already been called on this object. Note // that similar to the capacity of a 'vector', the returned capacity // has no bearing on the value of the 'Datum' array being constructed, // but does indicate at which point additional memory will be required // to grow the 'Datum' array being built. allocator_type get_allocator() const; // Return the allocator used by this object to supply memory. Note // that if no allocator was supplied at construction the default // allocator in effect at construction is used. SizeType size() const; // Return the size of the held 'Datum' array. The behavior is // undefined if 'commit' has already been called on this object. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ----------------------- // class DatumArrayBuilder // ----------------------- // ACCESSORS inline DatumArrayBuilder::SizeType DatumArrayBuilder::capacity() const { return d_capacity; } inline DatumArrayBuilder::allocator_type DatumArrayBuilder::get_allocator() const { return d_allocator; } inline DatumArrayBuilder::SizeType DatumArrayBuilder::size() const { if (d_capacity) { return *d_array.length(); // RETURN } return 0; } } // close package namespace } // 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 ----------------------------------