// ball_attributecontainerlist.h -*-C++-*- #ifndef INCLUDED_BALL_ATTRIBUTECONTAINERLIST #define INCLUDED_BALL_ATTRIBUTECONTAINERLIST #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a list of attribute container addresses. // //@CLASSES: // ball::AttributeContainerList: a list of container addresses // ball::AttributeContainerListIterator: an iterator over a container list // //@SEE_ALSO: ball_attribute, ball_attributecontainer // //@DESCRIPTION: This component defines a class 'ball::AttributeContainerList' // that provides a linked list of 'ball::AttributeContainer' object // *addresses*. Addresses can be prepended (to the front of the list) using // the 'pushFront()' method. The 'pushFront()' method returns an iterator that // can be used later to efficiently remove the added element. The // 'ball::AttributeContainerList' also provides a 'hasValue()' operation, that // returns 'true' if any of the attribute containers in the list contain the // supplied attribute, and 'false' otherwise. The // 'ball::AttributeContainerList' maintains a store of free list-nodes to // minimize the amount of memory allocation required if addresses are // frequently added and removed from the container. This component also // defines a class 'ball::AttributeContainerListIterator' (as well as the alias // 'ball::AttributeContainerList::iterator)' that provides an STL-style // iterator over the addresses in a 'ball::AttributeContainer'. // // This component participates in the implementation of "Rule-Based Logging". // For more information on how to use that feature, please see the package // level documentation and usage examples for "Rule-Based Logging". // ///Thread Safety ///------------- // 'ball::AttributeContainerList' is *const* *thread-safe*, meaning that // accessors may be invoked concurrently from different threads, but it is not // safe to access or modify a 'ball::AttributeContainerList' in one thread // while another thread modifies the same object. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Basic Usage of 'ball::AttributeContainerList' /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - // In the following example we demonstrate how to create a // 'ball::AttributeContainerList' object, how to add and remove elements from // the list, and how to walk the list of attribute container addresses. // // We start by creating three attribute sets that we will use to populate our // attribute container list. Note that this example uses the 'AttributeSet' // implementation of the 'ball::AttributeContainer' protocol defined in the // 'ball_attributecontainer' component documentation. //.. // AttributeSet s1, s2, s3; // s1.insert(ball::AttributeValue("Set1", 1)); // s2.insert(ball::AttributeValue("Set2", 2)); // s3.insert(ball::AttributeValue("Set3", 3)); //.. // We now create a 'ball::AttributeContainerList' and add the three attribute // container addresses to the list: //.. // ball::AttributeContainerList exampleList; // ball::AttributeContainerList::iterator s1Iter = exampleList.pushFront(&s1); // ball::AttributeContainerList::iterator s2Iter = exampleList.pushFront(&s2); // ball::AttributeContainerList::iterator s3Iter = exampleList.pushFront(&s3); //.. // We can use the 'hasValue()' operation to test which attribute value are // contained within the list of containers: //.. // assert(true == exampleList.hasValue("Set1", 1)); // assert(true == exampleList.hasValue("Set2", 2)); // assert(true == exampleList.hasValue("Set3", 3)); // // assert(false == exampleList.hasValue("Set1", 2)); // assert(false == exampleList.hasValue("Set2", 1)); // assert(false == exampleList.hasValue("Set4", 1)); //.. // We can use the iterators to efficiently remove elements from the list: //.. // exampleList.remove(s3Iter); //.. // Finally, we can use either the stream operator or the 'print()' method to // print the attributes within an attribute container list: //.. // bsl::cout << exampleList << bsl::endl; //.. // The resulting output will be the following: //.. // [ [ [ Set2 = 2 ] ] [ [ Set1 = 1 ] ] ] //.. // Note that the output shows the values in 's2' (i.e., '("Set2", 2)') and // then the values in 's1' (i.e., '("Set1", 1)'). #include <balscm_version.h> #include <bslma_allocator.h> #include <bslma_stdallocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_nestedtraitdeclaration.h> #include <bsl_iosfwd.h> namespace BloombergLP { namespace ball { class Attribute; class AttributeContainer; struct AttributeContainerList_Node; // ==================================== // class AttributeContainerListIterator // ==================================== class AttributeContainerListIterator { // This class provides an STL-style iterator over a sequence of // 'AttributeContainer' object addresses. The behavior of the 'operator*' // method is undefined unless the iterator is at a valid position in the // sequence of 'AttributeContainer' object addresses (i.e., not the "end") // and the referenced element has not been removed since the iterator was // constructed. // PRIVATE TYPES typedef AttributeContainerList_Node Node; // DATA Node *d_node_p; // current iterator location // FRIENDS friend bool operator==(const AttributeContainerListIterator&, const AttributeContainerListIterator&); friend class AttributeContainerList; public: // CREATORS AttributeContainerListIterator(); // Create an uninitialized iterator. AttributeContainerListIterator( const AttributeContainerListIterator& original); // Create an iterator having the same value as the specified // 'original' one. AttributeContainerListIterator(AttributeContainerList_Node *position); // Create an iterator at the specified 'position'. // ~AttributeContainerListIterator(); // Destroy this iterator. Note that this trivial destructor is // generated by the compiler. // MANIPULATORS AttributeContainerListIterator& operator=( const AttributeContainerListIterator& rhs); // Assign this iterator the value of the specified 'rhs' and return a // modifiable reference to this iterator. AttributeContainerListIterator operator++(int); // Advance this iterator to the next attribute container in the list // and return the value of this iterator. The behavior is undefined // unless the iterator is at a valid position in the list. AttributeContainerListIterator operator++(); // Advance this iterator to the next attribute container in the list // and return the value of the iterator prior to this method call. // The behavior is undefined unless the iterator is at a valid // position in the list. // ACCESSORS const AttributeContainer *operator*() const; // Return the address of the non-modifiable attribute container at // which this iterator is positioned. The behavior is undefined unless // this iterator is at a valid position in the list. bool valid() const; // Return 'true' if this iterator is at a valid position in the // sequence of 'AttributeContainer' addresses and 'false' otherwise. }; // FREE OPERATORS bool operator==(const AttributeContainerListIterator& lhs, const AttributeContainerListIterator& rhs); // Return 'true' if the specified 'lhs' and the specified 'rhs' iterators // have the same value and 'false' otherwise. Two iterators have the same // value if they refer to the same position in the same list, or if both // iterators are at an invalid position in the list (i.e., the "end" of the // list, or the default constructed value). bool operator!=(const AttributeContainerListIterator& lhs, const AttributeContainerListIterator& rhs); // Return 'true' if the specified 'lhs' and the specified 'rhs' iterators // do not have the same value and 'false' otherwise. Two iterators do not // have the same value if they differ in either the list to which they // refer or the position in the list object. // ============================ // class AttributeContainerList // ============================ class AttributeContainerList { // This class provides an in-core value-semantic list of // 'AttributeContainer' object addresses. Attribute container addresses // are added to this list using 'pushFront()', which returns an iterator // located at the new element. A 'AttributeContainerList::iterator' object // remains valid until the element referred to by the iterator is removed. // Attribute container addresses can be removed using either 'remove()', // 'removeAll()', or 'removeAllAndRelease()'. This list object attempts to // minimize the number of memory allocations it requires by placing the // memory for elements that have been released in a free memory store, and // re-using the memory when new elements are added. The 'removeAll()' // removes all the elements from the list, but does not release any // allocated memory (placing it in the free store). The // 'removeAllAndRelease()' operation removes all elements and releases all // allocated memory. Note that maintaining a free store is important for // this component because the expectation is that elements will be both // added and removed frequently. public: // TYPES typedef bsl::allocator<char> allocator_type; private: // PRIVATE TYPES typedef AttributeContainerList_Node Node; // DATA Node *d_head_p; // head of the linked list of elements Node *d_free_p; // head of the free store int d_length; // length of the list allocator_type d_allocator; // allocator public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(AttributeContainerList, bslma::UsesBslmaAllocator); // PUBLIC TYPES typedef AttributeContainerListIterator iterator; // An iterator over this list. // CREATORS AttributeContainerList(); explicit AttributeContainerList(const allocator_type& allocator); // Create an empty container list. Optionally specify an 'allocator' // (e.g., the address of a 'bslma::Allocator' object) to supply memory; // otherwise, the default allocator is used. AttributeContainerList( const AttributeContainerList& original, const allocator_type& allocator = allocator_type()); // Create a container list having the same value as the specified // 'original'. Optionally specify an 'allocator' (e.g., the address of // a 'bslma::Allocator' object) to supply memory; otherwise, the // default allocator is used. ~AttributeContainerList(); // Destroy this object. // MANIPULATORS AttributeContainerList& operator=(const AttributeContainerList& rhs); // Assign this container list the value of the specified 'rhs' one, and // return a reference to this list. iterator pushFront(const AttributeContainer *container); // Prepend the address of the specified 'container' to this list of // attribute container addresses, and return an iterator located at // the newly added list element. void remove(const iterator& element); // Remove the specified 'element' from this list. The behavior is // undefined unless 'element' is a valid iterator on this list and the // referenced address has not previously been removed (by either // 'remove()', 'removeAll()', or 'removeAllAndRelease()'. void removeAll(); // Remove all the elements from this list. After this operation // returns, 'numContainers()' will be 0. This operation adds all the // allocated memory to an internal free store, and does not deallocate // any memory. void removeAllAndRelease(); // Remove all the elements from this list and deallocate any allocated // memory. // ACCESSORS iterator begin() const; // Return an iterator positioned at the beginning of the list of // 'AttributeContainer' object addresses represented by this object. iterator end() const; // Return an iterator positioned one past the final // 'AttributeContainer' object address in the list of addresses // represented by this object. int numContainers() const; // Return the number of attribute container addresses currently in // this list. bool hasValue(const Attribute& value) const; // Return 'true' if the attribute having specified 'value' exists in // any of the attribute containers referred to by this object, and // 'false' otherwise. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Format this object to the specified output 'stream' at the // (absolute value of) the optionally specified indentation 'level' // and return a reference to 'stream'. If 'level' is specified, // optionally specify 'spacesPerLevel', 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. // Aspects 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. }; // FREE OPERATORS bool operator==(const AttributeContainerList& lhs, const AttributeContainerList& rhs); // Return 'true' if the specified 'lhs' and 'rhs' lists have the same // value, and 'false' otherwise. Two lists have the same value if they // have the same number of attribute container addresses, and the address // at each index position have the same value. inline bool operator!=(const AttributeContainerList& lhs, const AttributeContainerList& rhs); // Return 'true' if the specified 'lhs' and 'rhs' lists do not have the // same value, and 'false' otherwise. Two lists do not have the same // value if have differing numbers of attribute container addresses or any // of the addresses at corresponding indices have different values. inline bsl::ostream& operator<<(bsl::ostream& output, const AttributeContainerList& rhs); // Write a formatted description of the specified 'rhs' to the specified // 'stream' and return a reference to the modifiable 'stream'. // ================================= // class AttributeContainerList_Node // ================================= struct AttributeContainerList_Node { // This is an implementation type of 'AttributeContainerList' and should // not be used by clients of this package. A 'AttributeContainerList_Node' // represents a node in a 'AttributeContainerList' object. const AttributeContainer *d_value_p; // address value of this // element AttributeContainerList_Node *d_next_p; // next element AttributeContainerList_Node **d_prevNextAddr_p; // address of previous // element's next pointer }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------------------------ // class AttributeContainerListIterator // ------------------------------------ // CREATORS inline AttributeContainerListIterator::AttributeContainerListIterator() : d_node_p(0) { } inline AttributeContainerListIterator::AttributeContainerListIterator( AttributeContainerList_Node *position) : d_node_p(position) { } inline AttributeContainerListIterator::AttributeContainerListIterator( const AttributeContainerListIterator& original) : d_node_p(original.d_node_p) { } // MANIPULATORS inline AttributeContainerListIterator& AttributeContainerListIterator::operator=( const AttributeContainerListIterator& rhs) { d_node_p = rhs.d_node_p; return *this; } inline AttributeContainerListIterator AttributeContainerListIterator::operator++(int) { Node *current = d_node_p; d_node_p = d_node_p->d_next_p; return AttributeContainerListIterator(current); } inline AttributeContainerListIterator AttributeContainerListIterator::operator++() { d_node_p = d_node_p->d_next_p; return AttributeContainerListIterator(d_node_p); } // ACCESSORS inline const AttributeContainer * AttributeContainerListIterator::operator*() const { return d_node_p->d_value_p; } inline bool AttributeContainerListIterator::valid() const { return 0 != d_node_p; } // ============================ // class AttributeContainerList // ============================ // CREATORS inline AttributeContainerList::AttributeContainerList() : d_head_p(0) , d_free_p(0) , d_length(0) , d_allocator() { } inline AttributeContainerList::AttributeContainerList(const allocator_type& allocator) : d_head_p(0) , d_free_p(0) , d_length(0) , d_allocator(allocator) { } inline AttributeContainerList::~AttributeContainerList() { removeAllAndRelease(); } // ACCESSORS inline AttributeContainerList::iterator AttributeContainerList::begin() const { return iterator(d_head_p); } inline AttributeContainerList::iterator AttributeContainerList::end() const { return iterator(0); } inline int AttributeContainerList::numContainers() const { return d_length; } inline AttributeContainerList::allocator_type AttributeContainerList::get_allocator() const { return d_allocator; } } // close package namespace // FREE OPERATORS inline bool ball::operator==(const AttributeContainerListIterator& lhs, const AttributeContainerListIterator& rhs) { return lhs.d_node_p == rhs.d_node_p; } inline bool ball::operator!=(const AttributeContainerListIterator& lhs, const AttributeContainerListIterator& rhs) { return !(lhs == rhs); } inline bool ball::operator!=(const AttributeContainerList& lhs, const AttributeContainerList& rhs) { return !(lhs == rhs); } inline bsl::ostream& ball::operator<<(bsl::ostream& output, const AttributeContainerList& rhs) { return rhs.print(output, 0, -1); } } // 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 ----------------------------------