4 more associative containers.

Hi Everyone, This is my debut post on Boost, and I would like to introduce some container classes I made so they can be considered for inclusion into Boost. (I made a similar post on STLport, but members of STLport suggested that Boost would be a better forum because STLport only has standard containers.) The containers are called flex_set, flex_map, flex_multiset, and flex_multimap. They are similar to the 4 STL associative containers. There are two important differences between the STL containers and these: 1. You can search on any type that is comparable to the key_type, rather than just the key_type. (The STL associative containers only allows searches on the same type as the key.) 2. You do *not* need to create a temporary object of key_type to search through the containers. (The STL containers require you to create one temporary object to search for another.) The flex_set and related containers do not have these limitations because: a) several of the member functions are template member functions, b) and that allows the comparison functor used with the containers to be overloaded for each type that can be used for searching. Listing 1 shows the two limitations of std::set and the other associative containers. For this example, assume you have an Employee class, and you store them in a set which is ordered by employee name. Listing 1: class Employee { public: const std::string & GetName() const; // . . . other functions }; struct CompareEmployees : std::binary_function< const Employee *, const Employee *, bool > { // Can only do a comparison of one Employee record // to another Employee record. Can't compare to any // other type. inline bool operator () ( const Employee * l, const Employee * r ) const { return ( l->GetName() < r->GetName() ); } }; typedef std::set< Employee *, CompareEmployees > EmployeeSet; EmployeeSet employees; Employee * FindEmployee( const std::string & name ) { // This bogus object is just a temporary to find the real // object. All I want is to find an Employee record that // matches the given name, rather make such a record. Employee bogus( name ); EmployeeSet::iterator it( employees.find( &bogus ) ); return ( employees.end() == it ) ? 0 : *it; } Listing 2 shows all the member functions which are now templated. The non-templated versions of these functions inside std::set use the key_type. The Compare_Type template parameter in the flex_set functions is *not* one of the template parameters for the class itself. Listing 2: template < class Key, class Compare, class Alloc > class flex_set { // . . . other parts of flex_set class public: template< class Compare_Type > size_type erase( const Compare_Type & x ); template< class CompareType > size_type count( const CompareType & x ) const; template< class Compare_Type > iterator find( const Compare_Type & x ); template< class Compare_Type > const_iterator find( const Compare_Type & x ) const; template< class Compare_Type > iterator lower_bound ( const Compare_Type & x ); template< class Compare_Type > const_iterator lower_bound( const Compare_Type & x ) const; template< class Compare_Type > iterator upper_bound( const Compare_Type & x ); template< class Compare_Type > const_iterator upper_bound( const Compare_Type & x ) const; template< class Compare_Type > pair< iterator, iterator > equal_range( const Compare_Type & x ); template< class Compare_Type > pair< const_iterator, const_iterator > equal_range( const Compare_Type & x ) const; }; Other than accepting a reference to a const Compare_Type in some functions, the flex_set class is identical to the std::set. Even the basic implementation is the same. Like the std::set class, flex_set uses the comparison functor as a little policy class to determine how the elements are sorted. Although the std::set has no need for an overloaded functor, the flex_set's real flexibility comes into play when using overloaded functors. I can design into my functor the mechanism by which an Employee record can be compared to a std::string or to a C-style string. Listing 3 shows the overloaded comparison functor. Listing 3: struct CompareEmployees : std::binary_function< const Employee *, const Employee *, bool > { inline bool operator () ( const Employee * l, const Employee * r ) const { return ( l->GetName() < r->GetName() ); } inline bool operator () ( const Employee * l, const std::string & r ) const { return ( l->GetName() < r ); } inline bool operator () ( const std::string & l, const Employee * r ) const { return ( l < r->GetName() ); } inline bool operator () ( const Employee * l, const char * r ) const { return ( l->GetName() < r ); } inline bool operator () ( const char * l, const Employee * r ) const { return ( l < r->GetName() ); } }; The example shown in Listing 1 now becomes the function shown in Listing 4. Listing 4: typedef flex_set< Employee *, CompareEmployees > EmployeeSet; EmployeeSet employees; Employee * FindEmployee( const std::string & name ) { // No unnecessary temporary objects here! // And the code shows my intent of searching by name. EmployeeSet::iterator it( employees.find( name ) ); return ( employees.end() == it ) ? 0 : *it; } I just published an article describing these containers in issue #58 of Overload magazine http://www.accu.org/c++sig/public/Overload.html. The article explains various design decisions about the classes, and goes into more detail about the containers. You can also find a zip file of my implementation at http://www.richsposato.com/FlexSet.html along with a zip file containing a demo project. The implementation was made as a drop-in replacement for the associative containers that come with the GCC compiler. I made the demo project using MinGW. Because my implementation was designed for GCC's version of the STL, the classes don't compile cleanly with some other implementations of the STL. For that reason, they will be reimplemented for Boost, if they are accepted. Thanks for your consideration, Rich Sposato

On Mon, Feb 02, 2004 at 11:50:45PM -0800, Rich Sposato wrote:
The containers are called flex_set, flex_map, flex_multiset, and flex_multimap. They are similar to the 4 STL associative containers. There are two important differences between the STL containers and these: 1. You can search on any type that is comparable to the key_type, rather than just the key_type. (The STL associative containers only allows searches on the same type as the key.) 2. You do *not* need to create a temporary object of key_type to search through the containers. (The STL containers require you to create one temporary object to search for another.)
A good idea. I recall wishing for something like this a while ago; I don't remember if it stemmed from an actual problem in practice or just general unhappiness with the std:: interface in theory. (It might be even more swell if comparators could know about 'equivalence' as well, so you could test for equivalence using one user-defined function, rather than two calls like !c(x,y)&&!c(y,x).) Do you have have documentation of the new 'concepts'? Specifically it seems like flex_xxxx<T> uses a new ComparableTo<T,U> concept to place requirements on both the Comparator and the template arguments to methods like find(). -- -Brian McNamara (lorgon@cc.gatech.edu)

Brian McNamara wrote:
On Mon, Feb 02, 2004 at 11:50:45PM -0800, Rich Sposato wrote:
The containers are called flex_set, flex_map, flex_multiset, and flex_multimap. They are similar to the 4 STL associative containers. There are two important differences between the STL containers and these: 1. You can search on any type that is comparable to the key_type, rather than just the key_type. (The STL associative containers only allows searches on the same type as the key.) 2. You do *not* need to create a temporary object of key_type to search through the containers. (The STL containers require you to create one temporary object to search for another.)
A good idea. I recall wishing for something like this a while ago; I don't remember if it stemmed from an actual problem in practice or just general unhappiness with the std:: interface in theory.
I had difficulty storing and finding boost::intrusive_ptr<> in std::set<>. When I wanted to check if an arbitrary pointer value was in that set like: struct some {/*...*/}; typedef boost::intrusive_ptr<some> some_ptr; typedef std::set<some_ptr> some_set; some_set set; bool exists(some const* s) { return set.find(s) != set.end(); } void foo() { bool b = exists(reinterpret_cast<some*>(0xdeadbeaf)); // boom } as std::set::find() requires a key value, it ended up with constructing the smart pointer from a bogus value trying to do add_ref() and then release() on that value which led to runtime errors. If std::set<> had been able to use not a key value for find() but a key comparable value I would not have had any problems with that code. -- Maxim Yegorushkin MetaCommunications Engineering http://www.meta-comm.com/engineering/

"Rich Sposato" <rds@richsposato.com> wrote in message news:401F52D5.1090409@richsposato.com...
[...] The containers are called flex_set, flex_map, flex_multiset, and flex_multimap. They are similar to the 4 STL associative containers. There are two important differences between the STL containers and these: 1. You can search on any type that is comparable to the key_type, rather than just the key_type. (The STL associative containers only allows searches on the same type as the key.) 2. You do *not* need to create a temporary object of key_type to search through the containers. (The STL containers require you to create one temporary object to search for another.) [...]
This is pretty cool. I've had uses for this kind of thing many times, and always wrote a hack to solve it. Dave --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.571 / Virus Database: 361 - Release Date: 1/26/2004

I believe that a library named ``indexed_set,'' which has been proposed and is pending formal review, provides this functionality in addition to supporting multiple indices. -- Jeremy Maitin-Shepard

"Jeremy Maitin-Shepard" <jbms@attbi.com> wrote in message news:87u128yr3g.fsf@jbms.ath.cx...
I believe that a library named ``indexed_set,'' which has been proposed and is pending formal review, provides this functionality in addition to supporting multiple indices.
Are you sure it does the same thing? I was under the impression that Joaquin's library lets you define *additional* indexes, but what if you just want to use an existing index, but it is comparable to something other than the key_type? Dave --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.571 / Virus Database: 361 - Release Date: 1/26/2004

"David B. Held" <dheld@codelogicconsulting.com> writes:
"Jeremy Maitin-Shepard" <jbms@attbi.com> wrote in message news:87u128yr3g.fsf@jbms.ath.cx...
I believe that a library named ``indexed_set,'' which has been proposed and is pending formal review, provides this functionality in addition to supporting multiple indices.
Are you sure it does the same thing? I was under the impression that Joaquin's library lets you define *additional* indexes, but what if you just want to use an existing index, but it is comparable to something other than the key_type?
I am pretty certain that the library supports that. More commonly, however, the comparison process can be separated into key extraction, which obtains some key_type from the value_type, and then comparison on the key_type; this separation is supported by the library. I believe that in most cases the desire for a comparison predicate which operates on multiple types is actually (more conveniently) satisfied by being able to specify the key_type alone, rather than a value_type. -- Jeremy Maitin-Shepard

Rich Sposato wrote:
1. You can search on any type that is comparable to the key_type, rather than just the key_type. (The STL associative containers only allows searches on the same type as the key.)
BTW, there is also an extention in STLPort which supports comparisons like this. I often wondered why this isn't supported by the standard containers. Any idea? S.
participants (6)
-
Brian McNamara
-
David B. Held
-
Jeremy Maitin-Shepard
-
Maxim Yegorushkin
-
Rich Sposato
-
Stefan Slapeta