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