#include <boost/flyweight/locking_tag.hpp>
#include <boost/flyweight/holder_tag.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/named_recursive_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <typeinfo>

template<typename T,typename SegmentManager>
struct segment_allocator:
  boost::interprocess::allocator<T,typename SegmentManager::type>
{
  typedef boost::interprocess::allocator<T,typename SegmentManager::type> super;

  segment_allocator():super(SegmentManager::get()){}
  template<typename T2>
  segment_allocator(const segment_allocator<T2,SegmentManager>& x):super(x){}

  super& base(){return *this;}

  template<typename T2>
  struct rebind{
    typedef segment_allocator<T2,SegmentManager> other;
  };

  friend void swap(segment_allocator& x,segment_allocator& y)
  {
    swap(x.base(),y.base());
  }
};

template<typename SegmentManager,typename C>
struct segment_holder_class:boost::flyweights::holder_marker
{
  static C& get()
  {
    static C* pc=SegmentManager::get()->
      find_or_construct<C>(typeid(segment_holder_class).name())();
    return *pc;
  }
};

template<typename SegmentManager>
struct segment_holder:boost::flyweights::holder_marker
{
  template<typename C>
  struct apply
  {
    typedef segment_holder_class<SegmentManager,C> type;
  };
};

template<typename Name>
struct labeled_recursive_mutex
{
  typedef boost::interprocess::named_recursive_mutex mutex_type;

  operator mutex_type&()
  {
    static mutex_type mutex(
      boost::interprocess::open_or_create,Name::get());
    return mutex;
  }
};

template<typename Name>
struct labeled_locking:boost::flyweights::locking_marker
{
  typedef labeled_recursive_mutex<Name>                 mutex_type;
  typedef boost::interprocess::scoped_lock<
    typename labeled_recursive_mutex<Name>::mutex_type> lock_type;
};

#include <boost/flyweight.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <cassert>
#include <string>

using namespace boost::flyweights;
namespace ipc=boost::interprocess;

struct memory_dat_segment_manager
{
  typedef ipc::managed_mapped_file::segment_manager type;

  static type* get()
  {
    static ipc::managed_mapped_file* segment=
      new ipc::managed_mapped_file(ipc::open_or_create,"memory.dat",409600);
    return segment->get_segment_manager();
  }
};

struct mutex_name
{
  static const char* get(){return "7AD6D8E8-320B-12DC-82CF-F0B655D995AF";}
};

typedef ipc::basic_string<
  char,std::char_traits<char>,
  segment_allocator<char,memory_dat_segment_manager> > shm_string;

typedef flyweight<
  shm_string,
  hashed_factory<
    boost::hash<shm_string>,
    std::equal_to<shm_string>,
    segment_allocator<boost::mpl::_1,memory_dat_segment_manager>
  >,
  labeled_locking<mutex_name>,
  segment_holder<memory_dat_segment_manager>
> shm_string_flyweight;

int main()
{
  shm_string_flyweight x("hello"),y("hello"),z("bye");
  assert(x==y);
  assert(x!=z);
}

