diff options
Diffstat (limited to 'boost/flyweight/key_value.hpp')
-rw-r--r-- | boost/flyweight/key_value.hpp | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/boost/flyweight/key_value.hpp b/boost/flyweight/key_value.hpp new file mode 100644 index 0000000000..5ac1c0d57d --- /dev/null +++ b/boost/flyweight/key_value.hpp @@ -0,0 +1,238 @@ +/* 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. + */ + +#ifndef BOOST_FLYWEIGHT_KEY_VALUE_HPP +#define BOOST_FLYWEIGHT_KEY_VALUE_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include <boost/flyweight/detail/value_tag.hpp> +#include <boost/flyweight/key_value_fwd.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/preprocessor/repetition/enum_params.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_NAME explicit rep_type +#define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \ + :value_ptr(0) \ +{ \ + new(spc_ptr())key_type(BOOST_PP_ENUM_PARAMS(n,t)); \ +} +#include <boost/flyweight/detail/perfect_fwd.hpp> + + rep_type(const value_type& x):value_ptr(&x){} + + 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() + { + 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 */ + + key_type k(*key_ptr()); + 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); + } + + 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(); + } +}; + +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 */ + +#define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit rep_type +#define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \ + :key(BOOST_PP_ENUM_PARAMS(n,t)),value_ptr(0){} +#include <boost/flyweight/detail/perfect_fwd.hpp> + + rep_type(const value_type& x):key(no_key_from_value_failure()){} + + rep_type(const rep_type& x):key(x.key),value_ptr(0){} + + ~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(); + } + + static void copy_value(const rep_type&){} +}; + +} /* 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 |