boost/flyweight/detail/flyweight_core.hpp
/* Copyright 2006-2024 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_DETAIL_FLYWEIGHT_CORE_HPP
#define BOOST_FLYWEIGHT_DETAIL_FLYWEIGHT_CORE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/core/no_exceptions_support.hpp>
#include <boost/config/workaround.hpp>
#include <boost/flyweight/detail/perfect_fwd.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/type_traits/declval.hpp>
#include <utility>
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400))
#pragma warning(push)
#pragma warning(disable:4101) /* unreferenced local vars */
#endif
/* flyweight_core provides the inner implementation of flyweight<> by
* weaving together a value policy, a flyweight factory, a holder for the
* factory,a tracking policy and a locking policy.
*/
namespace boost{
namespace flyweights{
namespace detail{
template<
typename ValuePolicy,typename Tag,typename TrackingPolicy,
typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
>
class flyweight_core;
template<
typename ValuePolicy,typename Tag,typename TrackingPolicy,
typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
>
struct flyweight_core_tracking_helper
{
private:
typedef flyweight_core<
ValuePolicy,Tag,TrackingPolicy,
FactorySpecifier,LockingPolicy,
HolderSpecifier
> core;
typedef typename core::handle_type handle_type;
typedef typename core::entry_type entry_type;
public:
static const entry_type& entry(const handle_type& h)
{
return core::entry(h);
}
template<typename Checker>
static void erase(const handle_type& h,Checker chk)
{
typedef typename core::lock_type lock_type;
core::init();
lock_type lock(core::mutex());(void)lock;
if(chk(h))core::factory().erase(h);
}
};
/* ADL-based customization point for factories providing the undocumented
* insert_and_visit facility rather than regular insert. Default behavior is
* to erase the entry if visitation throws.
*/
template<typename Factory,typename Entry,typename F>
typename Factory::handle_type
insert_and_visit(Factory& fac,const Entry& x,F f)
{
typedef typename Factory::handle_type handle_type;
handle_type h(fac.insert(x));
BOOST_TRY{
f(fac.entry(h));
}
BOOST_CATCH(...){
fac().erase(h);
BOOST_RETHROW;
}
BOOST_CATCH_END
return h;
}
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template<typename Factory,typename Entry,typename F>
typename Factory::handle_type
insert_and_visit(Factory& fac,Entry&& x,F f)
{
typedef typename Factory::handle_type handle_type;
handle_type h(fac.insert(std::forward<Entry>(x)));
BOOST_TRY{
f(fac.entry(h));
}
BOOST_CATCH(...){
fac.erase(h);
BOOST_RETHROW;
}
BOOST_CATCH_END
return h;
}
#endif
template<
typename ValuePolicy,typename Tag,typename TrackingPolicy,
typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
>
class flyweight_core
{
public:
typedef typename ValuePolicy::key_type key_type;
typedef typename ValuePolicy::value_type value_type;
typedef typename ValuePolicy::rep_type rep_type;
typedef typename mpl::apply2<
typename TrackingPolicy::entry_type,
rep_type,
key_type
>::type entry_type;
typedef typename mpl::apply2<
FactorySpecifier,
entry_type,
key_type
>::type factory_type;
typedef typename factory_type::handle_type base_handle_type;
typedef typename mpl::apply2<
typename TrackingPolicy::handle_type,
base_handle_type,
flyweight_core_tracking_helper<
ValuePolicy,Tag,TrackingPolicy,
FactorySpecifier,LockingPolicy,
HolderSpecifier
>
>::type handle_type;
typedef typename LockingPolicy::mutex_type mutex_type;
typedef typename LockingPolicy::lock_type lock_type;
static bool init()
{
if(static_initializer)return true;
else{
holder_arg& a=holder_type::get();
static_factory_ptr=&a.factory;
static_mutex_ptr=&a.mutex;
static_initializer=(static_factory_ptr!=0);
return static_initializer;
}
}
/* insert overloads*/
#define BOOST_FLYWEIGHT_PERFECT_FWD_INSERT_BODY(args) \
{ \
return insert_rep(rep_type(BOOST_FLYWEIGHT_FORWARD(args))); \
}
BOOST_FLYWEIGHT_PERFECT_FWD(
static handle_type insert,
BOOST_FLYWEIGHT_PERFECT_FWD_INSERT_BODY)
#undef BOOST_FLYWEIGHT_PERFECT_FWD_INSERT_BODY
static handle_type insert(const value_type& x){return insert_value(x);}
static handle_type insert(value_type& x){return insert_value(x);}
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
static handle_type insert(const value_type&& x){return insert_value(x);}
static handle_type insert(value_type&& x){return insert_value(std::move(x));}
#endif
static const entry_type& entry(const base_handle_type& h)
{
return factory().entry(h);
}
static const value_type& value(const handle_type& h)
{
return static_cast<const rep_type&>(entry(h));
}
static const key_type& key(const handle_type& h)
BOOST_NOEXCEPT_IF(noexcept(
static_cast<const rep_type&>(boost::declval<const entry_type&>())))
{
return static_cast<const rep_type&>(entry(h));
}
static factory_type& factory()
{
return *static_factory_ptr;
}
static mutex_type& mutex()
{
return *static_mutex_ptr;
}
private:
struct holder_arg
{
factory_type factory;
mutex_type mutex;
};
typedef typename mpl::apply1<
HolderSpecifier,
holder_arg
>::type holder_type;
/* [key|copy|move]_construct_value: poor-man's pre-C++11 lambdas */
struct key_construct_value
{
void operator()(const entry_type& e)const
{
ValuePolicy::key_construct_value(static_cast<const rep_type&>(e));
}
};
struct copy_construct_value
{
copy_construct_value(const value_type& x_):x(x_){}
void operator()(const entry_type& e)const
{
ValuePolicy::copy_construct_value(static_cast<const rep_type&>(e),x);
}
const value_type& x;
};
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
struct move_construct_value
{
move_construct_value(value_type&& x_):x(x_){}
void operator()(const entry_type& e)const
{
ValuePolicy::move_construct_value(
static_cast<const rep_type&>(e),std::move(x));
}
value_type& x;
};
#endif
static handle_type insert_rep(const rep_type& x)
{
init();
entry_type e(x);
lock_type lock(mutex());(void)lock;
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
return static_cast<handle_type>(
insert_and_visit(factory(),std::move(e),key_construct_value()));
#else
return static_cast<handle_type>(
insert_and_visit(factory(),e,key_construct_value()));
#endif
}
static handle_type insert_value(const value_type& x)
{
init();
entry_type e((rep_type(x)));
lock_type lock(mutex());(void)lock;
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
return static_cast<handle_type>(
insert_and_visit(factory(),std::move(e),copy_construct_value(x)));
#else
return static_cast<handle_type>(
insert_and_visit(factory(),e,copy_construct_value(x)));
#endif
}
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
static handle_type insert_rep(rep_type&& x)
{
init();
entry_type e(std::move(x));
lock_type lock(mutex());(void)lock;
return static_cast<handle_type>(
insert_and_visit(factory(),std::move(e),key_construct_value()));
}
static handle_type insert_value(value_type&& x)
{
init();
entry_type e(rep_type(std::move(x)));
lock_type lock(mutex());(void)lock;
return static_cast<handle_type>(
insert_and_visit(
factory(),std::move(e),move_construct_value(std::move(x))));
}
#endif
static bool static_initializer;
static factory_type* static_factory_ptr;
static mutex_type* static_mutex_ptr;
};
template<
typename ValuePolicy,typename Tag,typename TrackingPolicy,
typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
>
bool
flyweight_core<
ValuePolicy,Tag,TrackingPolicy,
FactorySpecifier,LockingPolicy,HolderSpecifier>::static_initializer=
flyweight_core<
ValuePolicy,Tag,TrackingPolicy,
FactorySpecifier,LockingPolicy,HolderSpecifier>::init();
template<
typename ValuePolicy,typename Tag,typename TrackingPolicy,
typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
>
typename flyweight_core<
ValuePolicy,Tag,TrackingPolicy,
FactorySpecifier,LockingPolicy,HolderSpecifier>::factory_type*
flyweight_core<
ValuePolicy,Tag,TrackingPolicy,
FactorySpecifier,LockingPolicy,HolderSpecifier>::static_factory_ptr=0;
template<
typename ValuePolicy,typename Tag,typename TrackingPolicy,
typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
>
typename flyweight_core<
ValuePolicy,Tag,TrackingPolicy,
FactorySpecifier,LockingPolicy,HolderSpecifier>::mutex_type*
flyweight_core<
ValuePolicy,Tag,TrackingPolicy,
FactorySpecifier,LockingPolicy,HolderSpecifier>::static_mutex_ptr=0;
} /* namespace flyweights::detail */
} /* namespace flyweights */
} /* namespace boost */
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400))
#pragma warning(pop)
#endif
#endif