// bdlat_arrayfunctions.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BDLAT_ARRAYFUNCTIONS #define INCLUDED_BDLAT_ARRAYFUNCTIONS #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a namespace defining "array" functions. // //@CLASSES: // bdlat_ArrayFunctions: namespace for calling "array" functions // //@DESCRIPTION: The 'bdlat_ArrayFunctions' 'namespace' provided in this // component defines parameterized functions that expose "array" behavior for // "array" types. See the {'bdlat'} package-level documentation for a full // description of "array" types. // // The functions in this namespace allow users to: //: o obtain the number of elements in an array ('size'). //: o set the number of elements in an array ('resize'). //: o manipulate an element in an array using a parameterized manipulator //: ('manipulateElement'). and //: o access an element in an array using a parameterized accessor //: ('accessElement'). // // A type becomes part of the 'bdlat' "array" framework by creating, in the // namespace where the type is defined, overloads of the following two (free) // functions and two (free) function templates. Note that the placeholder // 'YOUR_TYPE' is not a template argument and should be replaced with the name // of the type being plugged into the framework. //.. // // MANIPULATORS // template <class MANIPULATOR> // int bdlat_arrayManipulateElement(YOUR_TYPE *array, // MANIPULATOR& manipulator, // int index); // // Invoke the specified 'manipulator' on the address of the element at // // the specified 'index' of the specified 'array'. Return the value // // from the invocation of 'manipulator'. The behavior is undefined // // unless '0 <= index' and 'index < bdlat_arraySize(*array)'. // // void resize(YOUR_TYPE *array, int newSize); // // Set the size of the specified modifiable 'array' to the specified // // 'newSize'. If 'newSize > bdlat_arraySize(*array)', then // // 'newSize - bdlat_arraySize(*array)' elements with default values // // (i.e., 'ElementType()') are appended to 'array'. If // // 'newSize < bdlat_arraySize(*array)', then the // // 'bdlat_arraySize(*array) - newSize' elements at the end of 'array' // // are destroyed. The behavior is undefined unless '0 <= newSize'. // // // ACCESSORS // template <class ACCESSOR> // int bdlat_arrayAccessElement(const YOUR_TYPE& array, // ACCESSOR& accessor, // int index); // // Invoke the specified 'accessor' on a 'const'-reference to the // // element at the specified 'index' of the specified 'array'. Return // // the value from the invocation of 'accessor'. The behavior is // // undefined unless '0 <= index' and 'index < bdlat_arraySize(array)'. // // bsl::size_t bdlat_arraySize(const YOUR_TYPE& array); // // Return the number of elements in the specified 'array'. //.. // The "array" type must also define two meta-functions in the // 'bdlat_ArrayFunctions' namespace: // //: o the meta-function 'IsArray' contains a compile-time constant 'VALUE' that //: is non-zero if the parameterized 'TYPE' exposes "array" behavior, and //: //: o the 'ElementType' meta-function contains a 'typedef' 'Type' that //: specifies the type of the element stored in the parameterized "array" //: type. // // Note that 'bsl::vector<TYPE>' is already part of the 'bdlat' // infrastructure for "array" types because this component also provides // overloads of the required functions and meta-function specializations. // ///Usage //------ // The following code illustrate the usage of this component. // ///Example 1: Defining an "Array" Type // - - - - - - - - - - - - - - - - - - // Suppose you had a type, 'mine::MyIntArray', that provides the essential // features of an "array" type. //.. // namespace BloombergLP { // namespace mine { // // class MyIntArray { // // int *d_data_p; // bsl::size_t d_size; // // public: // // CREATORS // MyIntArray() // : d_data_p(0) // , d_size(0) // { // } // // ~MyIntArray() // { // bsl::free(d_data_p); // } // // // MANIPULATORS // void resize(bsl::size_t newSize); // // int& value(bsl::size_t index) // { // assert(index < d_size); // // return d_data_p[index]; // } // // // ACCESSORS // const int& value(bsl::size_t index) const // { // assert(index < d_size); // // return d_data_p[index]; // } // // bsl::size_t size() const // { // return d_size; // } // }; // // void MyIntArray::resize(bsl::size_t newSize) // { // // Always match buffer to size exactly. // // if (d_size == newSize) { // return; // RETURN // } // // int *newData = static_cast<int *>(bsl::malloc(sizeof(int) // * newSize)); // if (d_size < newSize) { // bsl::memcpy(newData, d_data_p, d_size * sizeof(int)); // std::memset(newData + d_size, // 0, // (newSize - d_size) * sizeof(int)); // // } else { // bsl::memcpy(newData, d_data_p, newSize); // } // // bsl::free(d_data_p); // d_data_p = newData; // d_size = newSize; // } // // } // close namespace mine // } // close enterprise namespace //.. // We can now make 'mine::MyIntArray' expose "array" behavior by implementing // the necessary 'bdlat_ArrayFunctions' for 'MyIntArray' inside the 'mine' // namespace and defining the required meta-functions withing the // 'bdlat_ArrayFunctions' namespace. // // First, we should forward declare all the functions that we will implement // inside the 'mine' namespace: //.. // namespace BloombergLP { // namespace mine { // // // MANIPULATORS // template <class MANIPULATOR> // int bdlat_arrayManipulateElement(MyIntArray *array, // MANIPULATOR& manipulator, // int index); // // Invoke the specified 'manipulator' on the address of the element at // // the specified 'index' of the specified 'array'. Return the value // // from the invocation of 'manipulator'. The behavior is undefined // // unless '0 <= index' and 'index < bdlat_arraySize(*array)'. // // void bdlat_arrayResize(MyIntArray *array, int newSize); // // Set the size of the specified modifiable 'array' to the specified // // 'newSize'. If 'newSize > bdlat_arraySize(*array)', then // // 'newSize - bdlat_arraySize(*array)' elements with default values // // (i.e., 'ElementType()') are appended to 'array'. If // // 'newSize < bdlat_arraySize(*array)', then the // // 'bdlat_arraySize(*array) - newSize' elements at the end of 'array' // // are destroyed. The behavior is undefined unless '0 <= newSize'. // // // ACCESSORS // template <class ACCESSOR> // int bdlat_arrayAccessElement(const MyIntArray& array, // ACCESSOR& accessor, // int index); // // Invoke the specified 'accessor' on a 'const'-reference to the // // element at the specified 'index' of the specified 'array'. Return // // the value from the invocation of 'accessor'. The behavior is // // undefined unless '0 <= index' and 'index < bdlat_arraySize(array)'. // // bsl::size_t bdlat_arraySize(const MyIntArray& array); // // Return the number of elements in the specified 'array'. // // } // close namespace mine // } // close enterprise namespace //.. // Then, we will implement these functions. Recall that the two (non-template) // functions should be defined in some '.cpp' file, unless you choose to make // them 'inline' functions. //.. // namespace BloombergLP { // namespace mine { // // // MANIPULATORS // template <class MANIPULATOR> // int bdlat_arrayManipulateElement(MyIntArray *array, // MANIPULATOR& manipulator, // int index) // { // assert(array); // assert(0 <= index); // assert(static_cast<bsl::size_t>(index) < array->size()); // // return manipulator(&array->value(index)); // } // // void bdlat_arrayResize(MyIntArray *array, int newSize) // { // assert(array); // assert(0 <= newSize); // // array->resize(newSize); // } // // // ACCESSORS // template <class ACCESSOR> // int bdlat_arrayAccessElement(const MyIntArray& array, // ACCESSOR& accessor, // int index) // { // assert(0 <= index); // assert(static_cast<bsl::size_t>(index) < array.size()); // // return accessor(array.value(index)); // } // // bsl::size_t bdlat_arraySize(const MyIntArray& array) // { // return array.size(); // } // // } // close namespace mine // } // close enterprise namespace //.. // Finally, we specialize the 'IsArray' and 'ElementType' meta-functions // in the 'bdlat_ArrayFunctions' namespace for the // 'mine::MyIntArray' type: //.. // namespace BloombergLP { // namespace bdlat_ArrayFunctions { // // // TRAITS // template <> // struct IsArray<mine::MyIntArray> { // enum { VALUE = 1 }; // }; // // template <> // struct ElementType<mine::MyIntArray> { // typedef int Type; // }; // // } // close namespace bdlat_ArrayFunctions // } // close enterprise namespace //.. // This completes the 'bdlat' infrastructure for 'mine::MyIntArray' and // allows the generic software to recognize the type as an array abstraction. // ///Example 2: Using the Infrastructure Via General Methods ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - // The 'bdlat' "array" framework provides a set of fundamental operations // common to any "array" type. We can build upon these operations to make our // own utilities, or use them on our own types that are plugged into the // framework, like 'mine::MyIntArray', which we created in {Example 1}. For // example, we can use the (fundamental) operations in the // 'bdlat_ArrayFunctions' namespace to operate on 'mine::MyIntArray', even // though they have no knowledge of that type in particular: //.. // void usageMakeArray() // { // BSLMF_ASSERT(bdlat_ArrayFunctions::IsArray<mine::MyIntArray>::VALUE); // // mine::MyIntArray array; // assert(0 == bdlat_ArrayFunctions::size(array)); // // bdlat_ArrayFunctions::resize(&array, 8); // assert(8 == bdlat_ArrayFunctions::size(array)); // // bdlat_ArrayFunctions::resize(&array, 4); // assert(4 == bdlat_ArrayFunctions::size(array)); // } //.. // To perform operations on the elements of an array requires use of the // functions that employ accessor and manipulator functors. For example: //.. // template <class ELEMENT_TYPE> // class GetElementAccessor { // // // DATA // ELEMENT_TYPE *d_element_p; // // public: // // CREATORS // explicit GetElementAccessor(ELEMENT_TYPE *value) // : d_element_p(value) // { // } // // // MANIPULATORS // int operator()(const ELEMENT_TYPE& elementValue) // { // *d_element_p = elementValue; // return 0; // } // }; // // template<class ELEMENT_TYPE> // class SetElementManipulator { // // // DATA // ELEMENT_TYPE d_value; // // public: // // CREATORS // SetElementManipulator(const ELEMENT_TYPE& value) // : d_value(value) // { // } // // // ACCESSOR // int operator()(ELEMENT_TYPE *element) const // { // *element = d_value; // return 0; // } // }; //.. // Notice that these functors make few assumptions of 'ELEMENT_TYPE', merely // that it is copy constructable and copy assignable. // // With these definitions we can now use the generic functions to set and // get values from an 'mine::MyIntArray' object: //.. // void usageArrayElements() // { // mine::MyIntArray array; // bdlat_ArrayFunctions::resize(&array, 4); // // // Confirm initial array elements from resize. // // int value; // GetElementAccessor<int> accessor(&value); // // for (int index = 0; index < 4; ++index) { // int rc = bdlat_ArrayFunctions::accessElement(array, // accessor, // index); // assert(0 == rc); // assert(0 == value) // } // // // Set element 'index * 10' as its value; // // for (int index = 0; index < 4; ++index) { // SetElementManipulator<int> manipulator(index * 10); // // int rc = bdlat_ArrayFunctions::manipulateElement(&array, // manipulator, // index); // assert(0 == rc); // } // // // Confirm new value of each element. // // for (int index = 0; index < 4; ++index) { // int rc = bdlat_ArrayFunctions::accessElement(array, // accessor, // index); // assert(0 == rc); // assert(index * 10 == value); // } // } //.. // ///Example 3: Defining Utility Functions ///- - - - - - - - - - - - - - - - - - - // Creating functor objects for each operation can be tedious and error prone; // consequently, those types are often executed via utility functions. // // Suppose we want to create utilities for getting and setting the elements of // an arbitrary "array" type. We might define a utility 'struct', 'ArrayUtil', // a namespace for those functions: //.. // struct ArrayUtil { // // // CLASS METHODS // template <class ARRAY_TYPE> // static int getElement(typename bdlat_ArrayFunctions // ::ElementType<ARRAY_TYPE>::Type *value, // const ARRAY_TYPE& object, // int index) // // Load to the specified 'value' the element at the specified // // 'index' of the specified 'object' array. Return 0 if the // // element is successfully loaded to 'value', and a non-zero value // // otherwise. This function template requires that the specified // // 'ARRAY_TYPE' is a 'bdlat' "array" type. The behavior is // // undefined unless '0 <= index' and // // 'index < bdlat_ArrayFunctions::size(object)'. // { // BSLMF_ASSERT(bdlat_ArrayFunctions::IsArray<ARRAY_TYPE>::VALUE); // // typedef typename bdlat_ArrayFunctions // ::ElementType<ARRAY_TYPE>::Type ElementType; // // GetElementAccessor<ElementType> elementAccessor(value); // // return bdlat_ArrayFunctions::accessElement(object, // elementAccessor, // index); // } // // template <class ARRAY_TYPE> // static int setElement( // ARRAY_TYPE *object, // int index, // const typename bdlat_ArrayFunctions::ElementType<ARRAY_TYPE> // ::Type& value) // // Assign the specified 'value' to the element of the specified // // 'object' array at the specified 'index'. Return 0 if the // // element is successfully assigned to 'value', and a non-zero // // value otherwise. This function template requires that the // // specified 'ARRAY_TYPE' is a 'bdlat' "array" type. The behavior // // is undefined unless '0 <= index' and // // 'index < bdlat_ArrayFunctions::size(*object)'. // { // BSLMF_ASSERT(bdlat_ArrayFunctions::IsArray<ARRAY_TYPE>::VALUE); // // typedef typename bdlat_ArrayFunctions::ElementType<ARRAY_TYPE> // ::Type ElementType; // // SetElementManipulator<ElementType> manipulator(value); // // return bdlat_ArrayFunctions::manipulateElement(object, // manipulator, // index); // } // }; //.. // Now, we can use these functors to write generic utility functions for // getting and setting the value types of arbitrary "array" classes. //.. // void myUsageScenario() // { // mine::MyIntArray array; // bdlat_ArrayFunctions::resize(&array, 4); // // // Confirm initial values. // // for (int index = 0; index < 4; ++index) { // int value; // int rc = ArrayUtil::getElement(&value, array, index); // assert(0 == rc); // assert(0 == value); // } // // // Set element 'index * 10' as its value; // // for (int index = 0; index < 4; ++index) { // int value = index * 10; // int rc = ArrayUtil::setElement(&array, index, value); // assert(0 == rc); // } // // // Confirm value of each element. // // for (int index = 0; index < 4; ++index) { // int value; // int rc = ArrayUtil::getElement(&value, array, index); // assert(0 == rc); // assert(index * 10 == value); // } // } //.. // ///Example 4: Achieving Type Independence /// - - - - - - - - - - - - - - - - - - - // Suppose we have another type such as 'your::YourFloatArray', shown below: //.. // namespace BloombergLP { // namespace your { // // class MyFloatArray { // // float *d_data_p; // bsl::size_t d_size; // bsl::size_t d_capacity; // // public: // // CREATORS // MyFloatArray() // : d_data_p(0) // , d_size(0) // { // } // // ~MyFloatArray() // { // delete[] d_data_p; // } // // // MANIPULATORS // void setSize(bsl::size_t newSize); // Too large for inline. // // float& element(bsl::size_t index) // { // assert(index < d_size); // // return d_data_p[index]; // } // // // ACCESSORS // const float& element(bsl::size_t index) const // { // assert(index < d_size); // // return d_data_p[index]; // } // // bsl::size_t numElements() const // { // return d_size; // } // // bsl::size_t capacity() const // { // return d_capacity; // } // }; //.. // Notice that while there are many similarities to 'mine::MyIntArray', there // are also significant differences: //: o The element type is 'float', not 'int'. //: o Many of the accessors are named differently (e.g., 'numElements' instead //: of 'size', 'setSize' instead of 'resize'). //: o There is an additional attribute, 'capacity', because this class has a //: 'setSize' method (not shown) that reduces calls to the heap by over //: allocating when the size is increased beyond the current capacity. // // Nevertheless, since 'your::YourFloatArray' also provides the functions // and types expected by the 'bdlat' infrastructure (not shown) we can // successfully use 'your::FloatArray' value instead of 'mine::MyIntArray' // in the previous usage scenario, with no other changes: //.. // void yourUsageScenario() // { // your::YourFloatArray array; // bdlat_ArrayFunctions::resize(&array, 4); // // // Confirm initial values. // // for (int index = 0; index < 4; ++index) { // float value; // int rc = ArrayUtil::getElement(&value, array, index); // assert(0 == rc); // assert(0.0 == value); // } // // // Set element 'index * 10' as its value; // // for (int index = 0; index < 4; ++index) { // float value = static_cast<float>(index * 10); // int rc = ArrayUtil::setElement(&array, index, value); // assert(0 == rc); // } // // // Confirm value of each element. // // for (int index = 0; index < 4; ++index) { // float value; // int rc = ArrayUtil::getElement(&value, array, index); // assert(0 == rc); // assert(static_cast<float>(index * 10) == value); // } // } //.. // Notice that syntax and order of 'bdlat_ArrayFunctions' function // calls have not been changed. The only difference is that the element // type has changed from 'int' to 'float'. // // Finally, instead of defining a new "array" type, we could substitute the // existing type template 'bsl::vector'. Note that this component // provides specializations of the 'bdlat_ArrayFunctions' for that // type. Since the accessor and manipulator functions we created earlier are // type neutral, we can simply drop 'bsl::vector<bsl::string>' into our // familiar scenario: //.. // void anotherUsageScenario() // { // bsl::vector<bsl::string> array; // STANDARD ARRAY TYPE // bdlat_ArrayFunctions::resize(&array, 4); // // // Confirm initial values. // // for (int index = 0; index < 4; ++index) { // bsl::string value; // int rc = ArrayUtil::getElement(&value, array, index); // assert(0 == rc); // assert("" == value); // } // // // Set element 'index * 10' as its value; // // for (int index = 0; index < 4; ++index) { // bsl::ostringstream oss; oss << (index * 10); // int rc = ArrayUtil::setElement(&array, index, oss.str()); // assert(0 == rc); // } // // // Confirm value of each element. // // for (int index = 0; index < 4; ++index) { // bsl::string value; // int rc = ArrayUtil::getElement(&value, array, index); // // bsl::ostringstream oss; oss << (index * 10); // // assert(0 == rc); // assert(oss.str() == value); // } // } //.. #include <bdlscm_version.h> #include <bdlat_bdeatoverrides.h> #include <bslmf_metaint.h> #include <bsl_cstddef.h> #include <bsl_cstdlib.h> #include <bsl_vector.h> namespace BloombergLP { // ============================== // namespace bdlat_ArrayFunctions // ============================== namespace bdlat_ArrayFunctions { // This 'namespace' provides functions that expose "array" behavior for // "array" types. Specializations are provided for 'bsl::vector<TYPE>'. // See the component-level documentation for more information. // META-FUNCTIONS template <class TYPE> struct ElementType; // This meta-function should contain a typedef 'Type' that specifies // the type of element stored in an array of the parameterized 'TYPE'. template <class TYPE> struct IsArray { // This 'struct' should be specialized for third-party types that are // need to expose "array" behavior. See the component-level // documentation for further information. // TYPES enum { VALUE = 0 }; }; // MANIPULATORS template <class TYPE, class MANIPULATOR> int manipulateElement(TYPE *array, MANIPULATOR& manipulator, int index); // Invoke the specified 'manipulator' on the address of the element at // the specified 'index' of the specified 'array'. Return the value // from the invocation of 'manipulator'. The behavior is undefined // unless '0 <= index' and 'index < size(*array)'. template <class TYPE> void resize(TYPE *array, int newSize); // Set the size of the specified modifiable 'array' to the specified // 'newSize'. If 'newSize > size(array)', then 'newSize - size(array)' // elements with default values are appended to 'array'. If // 'newSize < size(array)', then the 'size(array) - newSize' elements // at the end of 'array' are destroyed. The behavior is undefined // unless '0 <= newSize'. // ACCESSORS template <class TYPE, class ACCESSOR> int accessElement(const TYPE& array, ACCESSOR& accessor, int index); // Invoke the specified 'accessor' on the non-modifiable element at the // specified 'index' of the specified 'array'. Return the value from // the invocation of 'accessor'. The behavior is undefined unless // '0 <= index' and 'index < size(array)'. template <class TYPE> bsl::size_t size(const TYPE& array); // Return the number of elements in the specified 'array'. } // close namespace bdlat_ArrayFunctions // ======================== // bsl::vector declarations // ======================== namespace bdlat_ArrayFunctions { // This namespace declaration adds the implementation of the "array" traits // for 'bsl::vector' to 'bdlat_ArrayFunctions'. Note that 'bsl::vector' is // the canonical "array" type. // META-FUNCTIONS template <class TYPE, class ALLOC> struct IsArray<bsl::vector<TYPE, ALLOC> > : bslmf::MetaInt<1> { }; template <class TYPE, class ALLOC> struct ElementType<bsl::vector<TYPE, ALLOC> > { typedef TYPE Type; }; // MANIPULATORS template <class TYPE, class ALLOC, class MANIPULATOR> int bdlat_arrayManipulateElement(bsl::vector<TYPE, ALLOC> *array, MANIPULATOR& manipulator, int index); template <class TYPE, class ALLOC> void bdlat_arrayResize(bsl::vector<TYPE, ALLOC> *array, int newSize); // ACCESSORS template <class TYPE, class ALLOC, class ACCESSOR> int bdlat_arrayAccessElement(const bsl::vector<TYPE, ALLOC>& array, ACCESSOR& accessor, int index); template <class TYPE, class ALLOC> bsl::size_t bdlat_arraySize(const bsl::vector<TYPE, ALLOC>& array); } // close namespace bdlat_ArrayFunctions // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------------- // namespace-level functions // ------------------------- // MANIPULATORS template <class TYPE, class MANIPULATOR> inline int bdlat_ArrayFunctions::manipulateElement(TYPE *array, MANIPULATOR& manipulator, int index) { return bdlat_arrayManipulateElement(array, manipulator, index); } template <class TYPE> inline void bdlat_ArrayFunctions::resize(TYPE *array, int newSize) { bdlat_arrayResize(array, newSize); } // ACCESSORS template <class TYPE, class ACCESSOR> inline int bdlat_ArrayFunctions::accessElement(const TYPE& array, ACCESSOR& accessor, int index) { return bdlat_arrayAccessElement(array, accessor, index); } template <class TYPE> inline bsl::size_t bdlat_ArrayFunctions::size(const TYPE& array) { return bdlat_arraySize(array); } // ----------------------- // bsl::vector definitions // ----------------------- // MANIPULATORS template <class TYPE, class ALLOC, class MANIPULATOR> inline int bdlat_ArrayFunctions::bdlat_arrayManipulateElement( bsl::vector<TYPE, ALLOC> *array, MANIPULATOR& manipulator, int index) { TYPE& element = (*array)[index]; return manipulator(&element); } template <class TYPE, class ALLOC> inline void bdlat_ArrayFunctions::bdlat_arrayResize(bsl::vector<TYPE, ALLOC> *array, int newSize) { array->resize(newSize); } // ACCESSORS template <class TYPE, class ALLOC, class ACCESSOR> inline int bdlat_ArrayFunctions::bdlat_arrayAccessElement( const bsl::vector<TYPE, ALLOC>& array, ACCESSOR& accessor, int index) { return accessor(array[index]); } template <class TYPE, class ALLOC> inline bsl::size_t bdlat_ArrayFunctions::bdlat_arraySize( const bsl::vector<TYPE, ALLOC>& array) { return array.size(); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 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 ----------------------------------