You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
238 lines
6.1 KiB
238 lines
6.1 KiB
/* 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
|
|
|