Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

libs/flyweight/example/custom_factory.cpp

/* Boost.Flyweight example of custom factory.
 *
 * Copyright 2006-2008 Joaquin M Lopez Munoz.
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * See http://www.boost.org/libs/flyweight for library home page.
 */

/* We include the default components of Boost.Flyweight except the factory,
 * which will be provided by ourselves.
 */
#include <boost/flyweight/flyweight.hpp>
#include <boost/flyweight/factory_tag.hpp>
#include <boost/flyweight/static_holder.hpp>
#include <boost/flyweight/simple_locking.hpp>
#include <boost/flyweight/refcounted.hpp>
#include <boost/tokenizer.hpp>
#include <functional>
#include <iostream>
#include <set>

using namespace boost::flyweights;

/* custom factory based on std::set with some logging capabilities */

/* Entry is the type of the stored objects. Value is the type
 * on which flyweight operates, that is, the T in flyweoght<T>. It
 * is guaranteed that Entry implicitly converts to const Value&.
 * The factory class could accept other template arguments (for
 * instance, a comparison predicate for the values), we leave it like
 * that for simplicity.
 */

template<typename Entry,typename Key>
class verbose_factory_class
{ 
  /* Entry store. Since Entry is implicitly convertible to const Key&,
   * we can directly use std::less<Key> as the comparer for std::set.
   */

  typedef std::set<Entry,std::less<Key> > store_type;

  store_type store;

public:
  typedef typename store_type::iterator handle_type;

  handle_type insert(const Entry& x)
  {
    /* locate equivalent entry or insert otherwise */

    std::pair<handle_type, bool> p=store.insert(x);
    if(p.second){ /* new entry */
      std::cout<<"new: "<<(const Key&)x<<std::endl;
    }
    else{         /* existing entry */
      std::cout<<"hit: "<<(const Key&)x<<std::endl;
    }
    return p.first;
  }

  void erase(handle_type h)
  {
    std::cout<<"del: "<<(const Key&)*h<<std::endl;
    store.erase(h);
  }

  const Entry& entry(handle_type h)
  {
    return *h; /* handle_type is an iterator */
  }
};

/* Specifier for verbose_factory_class. The simplest way to tag
 * this struct as a factory specifier, so that flyweight<> accepts it
 * as such, is by deriving from boost::flyweights::factory_marker.
 * See the documentation for info on alternative tagging methods.
 */

struct verbose_factory: factory_marker
{
  template<typename Entry,typename Key>
  struct apply
  {
    typedef verbose_factory_class<Entry,Key> type;
  } ;
};

/* ready to use it */

typedef flyweight<std::string,verbose_factory> fw_string;

int main()
{
  typedef boost::tokenizer<boost::char_separator<char> > text_tokenizer;


  std::string text=
    "I celebrate myself, and sing myself, "
    "And what I assume you shall assume, "
    "For every atom belonging to me as good belongs to you. "

    "I loafe and invite my soul, "
    "I lean and loafe at my ease observing a spear of summer grass. "

    "My tongue, every atom of my blood, form'd from this soil, this air, "
    "Born here of parents born here from parents the same, and their "
    "    parents the same, "
    "I, now thirty-seven years old in perfect health begin, "
    "Hoping to cease not till death.";

  std::vector<fw_string> v;

  text_tokenizer tok(text,boost::char_separator<char>(" \t\n.,;:!?'\"-"));
  for(text_tokenizer::iterator it=tok.begin();it!=tok.end();){
    v.push_back(fw_string(*it++));
  }
  
  return 0;
}