Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Extended functionality: Configurable containers

Configurable tree-based associative ordered containers
Configurable vectors

set, multiset, map and multimap associative containers are implemented as binary search trees which offer the needed complexity and stability guarantees required by the C++ standard for associative containers.

Boost.Container offers the possibility to configure at compile time some parameters of the binary search tree implementation. This configuration is passed as the last template parameter and defined using the utility class tree_assoc_options. The following parameters can be configured:

  • The underlying tree implementation type (tree_type). By default these containers use a red-black tree but the user can use other tree types:
  • Whether the size saving mechanisms are used to implement the tree nodes (optimize_size). By default this option is activated and is only meaningful to red-black and avl trees (in other cases, this option will be ignored). This option will try to put rebalancing metadata inside the "parent" pointer of the node if the pointer type has enough alignment. Usually, due to alignment issues, the metadata uses the size of a pointer yielding to four pointer size overhead per node, whereas activating this option usually leads to 3 pointer size overhead. Although some mask operations must be performed to extract data from this special "parent" pointer, in several systems this option also improves performance due to the improved cache usage produced by the node size reduction.

See the following example to see how tree_assoc_options can be used to customize these containers:

#include <boost/container/set.hpp>

//Make sure assertions are active
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <cassert>

int main ()
{
   using namespace boost::container;

   //First define several options
   //

   //This option specifies an AVL tree based associative container
   typedef tree_assoc_options< tree_type<avl_tree> >::type AVLTree;

   //This option specifies an AVL tree based associative container
   //disabling node size optimization.
   typedef tree_assoc_options< tree_type<avl_tree>
                             , optimize_size<false> >::type AVLTreeNoSizeOpt;

   //This option specifies an Splay tree based associative container
   typedef tree_assoc_options< tree_type<splay_tree> >::type SplayTree;

   //Now define new tree-based associative containers
   //

   //AVLTree based set container
   typedef set<int, std::less<int>, std::allocator<int>, AVLTree> AvlSet;

   //AVLTree based set container without size optimization
   typedef set<int, std::less<int>, std::allocator<int>, AVLTreeNoSizeOpt> AvlSetNoSizeOpt;

   //Splay tree based multiset container
   typedef multiset<int, std::less<int>, std::allocator<int>, SplayTree> SplayMultiset;

   //Use them
   //
   AvlSet avl_set;
   avl_set.insert(0);
   assert(avl_set.find(0) != avl_set.end());

   AvlSetNoSizeOpt avl_set_no_szopt;
   avl_set_no_szopt.insert(1);
   avl_set_no_szopt.insert(1);
   assert(avl_set_no_szopt.count(1) == 1);

   SplayMultiset splay_mset;
   splay_mset.insert(2);
   splay_mset.insert(2);
   assert(splay_mset.count(2) == 2);
   return 0;
}

Boost.Container offers the possibility to configure at compile time some parameters of vector implementation. This configuration is passed as the last template parameter and defined using the utility class vector_options. The following parameters can be configured:

  • growth_factor: the growth policy of the vector. The rate at which the capacity of a vector grows is implementation dependent and implementations choose exponential growth in order to meet the amortized constant time requirement for push_back. A higher growth factor will make it faster as it will require less data movement, but it will have a greater memory impact (on average, more memory will be unused). A user can provide it's own implementation and some predefined policies are available: growth_factor_50, growth_factor_60 and growth_factor_100.
  • stored_size: the type that will be used to store size-related parameters inside of the vector. Sometimes, when the maximum capacity to be used is much less than the theoretical maximum that a vector can hold, it's interesting to use smaller unsigned integer types to represent size() and capacity() inside vector, so that the size of an empty vector is minimized and cache performance might be improved. See stored_size for more details.

See the following example to see how vector_options can be used to customize vector container:

#include <boost/container/vector.hpp>
#include <boost/static_assert.hpp>

//Make sure assertions are active
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <cassert>

int main ()
{
   using namespace boost::container;

   //This option specifies that a vector that will use "unsigned char" as
   //the type to store capacity or size internally.
   typedef vector_options< stored_size<unsigned char> >::type size_option_t;

   //Size-optimized vector is smaller than the default one.
   typedef vector<int, new_allocator<int>, size_option_t > size_optimized_vector_t;
   BOOST_STATIC_ASSERT(( sizeof(size_optimized_vector_t) < sizeof(vector<int>) ));

   //Requesting capacity for more elements than representable by "unsigned char"
   //is an error in the size optimized vector.
   bool exception_thrown = false;
   try       { size_optimized_vector_t v(256); }
   catch(...){ exception_thrown = true;        }
   assert(exception_thrown == true);

   //This option specifies that a vector will increase its capacity 50%
   //each time the previous capacity was exhausted.
   typedef vector_options< growth_factor<growth_factor_50> >::type growth_50_option_t;

   //Fill the vector until full capacity is reached
   vector<int, new_allocator<int>, growth_50_option_t > growth_50_vector(5, 0);
   const std::size_t old_cap = growth_50_vector.capacity();
   growth_50_vector.resize(old_cap);

   //Now insert an additional item and check the new buffer is 50% bigger
   growth_50_vector.push_back(1);
   assert(growth_50_vector.capacity() == old_cap*3/2);

   return 0;
}


PrevUpHomeNext