| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 | /* Copyright 2006-2018 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. */#ifndef BOOST_FLYWEIGHT_KEY_VALUE_HPP#define BOOST_FLYWEIGHT_KEY_VALUE_HPP#if defined(_MSC_VER)#pragma once#endif#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */#include <boost/detail/workaround.hpp>#include <boost/flyweight/detail/perfect_fwd.hpp>#include <boost/flyweight/detail/value_tag.hpp>#include <boost/flyweight/key_value_fwd.hpp>#include <boost/mpl/assert.hpp>#include <boost/type_traits/aligned_storage.hpp>#include <boost/type_traits/alignment_of.hpp> #include <boost/type_traits/is_same.hpp>#include <new>/* key-value policy: flywewight lookup is based on Key, which also serves * to construct Value only when needed (new factory entry). key_value is * used to avoid the construction of temporary values when such construction * is expensive. * Optionally, KeyFromValue extracts the key from a value, which * is needed in expressions like this: * *  typedef flyweight<key_value<Key,Value> > fw_t; *  fw_t  fw; *  Value v; *  fw=v; // no key explicitly given * * If no KeyFromValue is provided, this latter expression fails to compile. */namespace boost{namespace flyweights{namespace detail{template<typename Key,typename Value,typename KeyFromValue>struct optimized_key_value:value_marker{  typedef Key   key_type;  typedef Value value_type;  class rep_type  {  public:    /* template ctors */#define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args)       \  :value_ptr(0)                                          \{                                                        \  new(spc_ptr())key_type(BOOST_FLYWEIGHT_FORWARD(args)); \}  BOOST_FLYWEIGHT_PERFECT_FWD(    explicit rep_type,    BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)#undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY    rep_type(const rep_type& x):value_ptr(x.value_ptr)    {      if(!x.value_ptr)new(key_ptr())key_type(*x.key_ptr());    }    rep_type(const value_type& x):value_ptr(&x){}#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)    rep_type(rep_type&& x):value_ptr(x.value_ptr)    {      if(!x.value_ptr)new(key_ptr())key_type(std::move(*x.key_ptr()));    }    rep_type(value_type&& x):value_ptr(&x){}#endif    ~rep_type()    {      if(!value_ptr)       key_ptr()->~key_type();      else if(value_cted())value_ptr->~value_type();    }    operator const key_type&()const    {      if(value_ptr)return key_from_value(*value_ptr);      else         return *key_ptr();    }    operator const value_type&()const    {      /* This is always called after construct_value() or copy_value(),       * so we access spc directly rather than through value_ptr to       * save us an indirection.       */      return *static_cast<value_type*>(spc_ptr());    }  private:    friend struct optimized_key_value;    void* spc_ptr()const{return static_cast<void*>(&spc);}    bool  value_cted()const{return value_ptr==spc_ptr();}    key_type* key_ptr()const    {      return static_cast<key_type*>(static_cast<void*>(&spc));    }    static const key_type& key_from_value(const value_type& x)    {      KeyFromValue k;      return k(x);    }    void construct_value()const    {      if(!value_cted()){        /* value_ptr must be ==0, oherwise copy_value would have been called */#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)        key_type k(std::move(*key_ptr()));#else        key_type k(*key_ptr());#endif        key_ptr()->~key_type();        value_ptr= /* guarantees key won't be re-dted at ~rep_type if the */          static_cast<value_type*>(spc_ptr())+1; /* next statement throws */        value_ptr=new(spc_ptr())value_type(k);      }    }    void copy_value()const    {      if(!value_cted())value_ptr=new(spc_ptr())value_type(*value_ptr);    }#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)    void move_value()const    {      if(!value_cted())value_ptr=        new(spc_ptr())value_type(std::move(const_cast<value_type&>(*value_ptr)));    }#endif    mutable typename boost::aligned_storage<      (sizeof(key_type)>sizeof(value_type))?        sizeof(key_type):sizeof(value_type),      (boost::alignment_of<key_type>::value >       boost::alignment_of<value_type>::value)?        boost::alignment_of<key_type>::value:        boost::alignment_of<value_type>::value    >::type                                    spc;    mutable const value_type*                  value_ptr;  };  static void construct_value(const rep_type& r)  {    r.construct_value();  }  static void copy_value(const rep_type& r)  {    r.copy_value();  }#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)  static void move_value(const rep_type& r)  {    r.move_value();  }#endif};template<typename Key,typename Value>struct regular_key_value:value_marker{  typedef Key   key_type;  typedef Value value_type;  class rep_type  {  public:    /* template ctors */#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)&&\    !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)&&\    BOOST_WORKAROUND(__GNUC__,<=4)&&(__GNUC__<4||__GNUC_MINOR__<=4)/* GCC 4.4.2 (and probably prior) bug: the default ctor generated by the * variadic temmplate ctor below fails to value-initialize key. */    rep_type():key(),value_ptr(0){}#endif#define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \  :key(BOOST_FLYWEIGHT_FORWARD(args)),value_ptr(0){}  BOOST_FLYWEIGHT_PERFECT_FWD(    explicit rep_type,    BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)#undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY    rep_type(const rep_type& x):key(x.key),value_ptr(0){}    rep_type(const value_type&):key(no_key_from_value_failure()){}#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)    rep_type(rep_type&& x):key(std::move(x.key)),value_ptr(0){}    rep_type(value_type&&):key(no_key_from_value_failure()){}#endif    ~rep_type()    {      if(value_ptr)value_ptr->~value_type();    }    operator const key_type&()const{return key;}    operator const value_type&()const    {      /* This is always called after construct_value(),so we access spc       * directly rather than through value_ptr to save us an indirection.       */      return *static_cast<value_type*>(spc_ptr());    }  private:    friend struct regular_key_value;    void* spc_ptr()const{return static_cast<void*>(&spc);}    struct no_key_from_value_failure    {      BOOST_MPL_ASSERT_MSG(        false,        NO_KEY_FROM_VALUE_CONVERSION_PROVIDED,        (key_type,value_type));      operator const key_type&()const;    };    void construct_value()const    {      if(!value_ptr)value_ptr=new(spc_ptr())value_type(key);    }    key_type                                 key;    mutable typename boost::aligned_storage<      sizeof(value_type),      boost::alignment_of<value_type>::value    >::type                                  spc;    mutable const value_type*                value_ptr;  };  static void construct_value(const rep_type& r)  {    r.construct_value();  }  /* copy_value() and move_value() can't really ever be called, provided to avoid   * compile errors (it is the no_key_from_value_failure compile error we want to   * appear in these cases).   */  static void copy_value(const rep_type&){}#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)  static void move_value(const rep_type&){}#endif};} /* namespace flyweights::detail */template<typename Key,typename Value,typename KeyFromValue>struct key_value:  mpl::if_<    is_same<KeyFromValue,no_key_from_value>,    detail::regular_key_value<Key,Value>,    detail::optimized_key_value<Key,Value,KeyFromValue>  >::type{};} /* namespace flyweights */} /* namespace boost */#endif
 |