summaryrefslogtreecommitdiff
path: root/boost/flyweight/key_value.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/flyweight/key_value.hpp')
-rw-r--r--boost/flyweight/key_value.hpp238
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