Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:53

0001 /* Copyright 2006-2018 Joaquin M Lopez Munoz.
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * http://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * See http://www.boost.org/libs/flyweight for library home page.
0007  */
0008 
0009 #ifndef BOOST_FLYWEIGHT_KEY_VALUE_HPP
0010 #define BOOST_FLYWEIGHT_KEY_VALUE_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
0017 #include <boost/detail/workaround.hpp>
0018 #include <boost/flyweight/detail/perfect_fwd.hpp>
0019 #include <boost/flyweight/detail/value_tag.hpp>
0020 #include <boost/flyweight/key_value_fwd.hpp>
0021 #include <boost/mpl/assert.hpp>
0022 #include <boost/type_traits/aligned_storage.hpp>
0023 #include <boost/type_traits/alignment_of.hpp> 
0024 #include <boost/type_traits/is_same.hpp>
0025 #include <new>
0026 
0027 /* key-value policy: flywewight lookup is based on Key, which also serves
0028  * to construct Value only when needed (new factory entry). key_value is
0029  * used to avoid the construction of temporary values when such construction
0030  * is expensive.
0031  * Optionally, KeyFromValue extracts the key from a value, which
0032  * is needed in expressions like this:
0033  *
0034  *  typedef flyweight<key_value<Key,Value> > fw_t;
0035  *  fw_t  fw;
0036  *  Value v;
0037  *  fw=v; // no key explicitly given
0038  *
0039  * If no KeyFromValue is provided, this latter expression fails to compile.
0040  */
0041 
0042 namespace boost{
0043 
0044 namespace flyweights{
0045 
0046 namespace detail{
0047 
0048 template<typename Key,typename Value,typename KeyFromValue>
0049 struct optimized_key_value:value_marker
0050 {
0051   typedef Key   key_type;
0052   typedef Value value_type;
0053 
0054   class rep_type
0055   {
0056   public:
0057     /* template ctors */
0058 
0059 #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args)       \
0060   :value_ptr(0)                                          \
0061 {                                                        \
0062   new(spc_ptr())key_type(BOOST_FLYWEIGHT_FORWARD(args)); \
0063 }
0064 
0065   BOOST_FLYWEIGHT_PERFECT_FWD(
0066     explicit rep_type,
0067     BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)
0068 
0069 #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
0070 
0071     rep_type(const rep_type& x):value_ptr(x.value_ptr)
0072     {
0073       if(!x.value_ptr)new(key_ptr())key_type(*x.key_ptr());
0074     }
0075 
0076     rep_type(const value_type& x):value_ptr(&x){}
0077 
0078 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0079     rep_type(rep_type&& x):value_ptr(x.value_ptr)
0080     {
0081       if(!x.value_ptr)new(key_ptr())key_type(std::move(*x.key_ptr()));
0082     }
0083 
0084     rep_type(value_type&& x):value_ptr(&x){}
0085 #endif
0086 
0087     ~rep_type()
0088     {
0089       if(!value_ptr)       key_ptr()->~key_type();
0090       else if(value_cted())value_ptr->~value_type();
0091     }
0092 
0093     operator const key_type&()const
0094     {
0095       if(value_ptr)return key_from_value(*value_ptr);
0096       else         return *key_ptr();
0097     }
0098 
0099     operator const value_type&()const
0100     {
0101       /* This is always called after construct_value() or copy_value(),
0102        * so we access spc directly rather than through value_ptr to
0103        * save us an indirection.
0104        */
0105 
0106       return *static_cast<value_type*>(spc_ptr());
0107     }
0108 
0109   private:
0110     friend struct optimized_key_value;
0111 
0112     void* spc_ptr()const{return static_cast<void*>(&spc);}
0113     bool  value_cted()const{return value_ptr==spc_ptr();}
0114 
0115     key_type* key_ptr()const
0116     {
0117       return static_cast<key_type*>(static_cast<void*>(&spc));
0118     }
0119 
0120     static const key_type& key_from_value(const value_type& x)
0121     {
0122       KeyFromValue k;
0123       return k(x);
0124     }
0125 
0126     void construct_value()const
0127     {
0128       if(!value_cted()){
0129         /* value_ptr must be ==0, oherwise copy_value would have been called */
0130 
0131 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0132         key_type k(std::move(*key_ptr()));
0133 #else
0134         key_type k(*key_ptr());
0135 #endif
0136 
0137         key_ptr()->~key_type();
0138         value_ptr= /* guarantees key won't be re-dted at ~rep_type if the */
0139           static_cast<value_type*>(spc_ptr())+1; /* next statement throws */
0140         value_ptr=new(spc_ptr())value_type(k);
0141       }
0142     }
0143 
0144     void copy_value()const
0145     {
0146       if(!value_cted())value_ptr=new(spc_ptr())value_type(*value_ptr);
0147     }
0148 
0149 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0150     void move_value()const
0151     {
0152       if(!value_cted())value_ptr=
0153         new(spc_ptr())value_type(std::move(const_cast<value_type&>(*value_ptr)));
0154     }
0155 #endif
0156 
0157     mutable typename boost::aligned_storage<
0158       (sizeof(key_type)>sizeof(value_type))?
0159         sizeof(key_type):sizeof(value_type),
0160       (boost::alignment_of<key_type>::value >
0161        boost::alignment_of<value_type>::value)?
0162         boost::alignment_of<key_type>::value:
0163         boost::alignment_of<value_type>::value
0164     >::type                                    spc;
0165     mutable const value_type*                  value_ptr;
0166   };
0167 
0168   static void construct_value(const rep_type& r)
0169   {
0170     r.construct_value();
0171   }
0172 
0173   static void copy_value(const rep_type& r)
0174   {
0175     r.copy_value();
0176   }
0177 
0178 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0179   static void move_value(const rep_type& r)
0180   {
0181     r.move_value();
0182   }
0183 #endif
0184 };
0185 
0186 template<typename Key,typename Value>
0187 struct regular_key_value:value_marker
0188 {
0189   typedef Key   key_type;
0190   typedef Value value_type;
0191 
0192   class rep_type
0193   {
0194   public:
0195     /* template ctors */
0196 
0197 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)&&\
0198     !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)&&\
0199     BOOST_WORKAROUND(__GNUC__,<=4)&&(__GNUC__<4||__GNUC_MINOR__<=4)
0200 
0201 /* GCC 4.4.2 (and probably prior) bug: the default ctor generated by the
0202  * variadic temmplate ctor below fails to value-initialize key.
0203  */
0204 
0205     rep_type():key(),value_ptr(0){}
0206 #endif
0207 
0208 #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
0209   :key(BOOST_FLYWEIGHT_FORWARD(args)),value_ptr(0){}
0210 
0211   BOOST_FLYWEIGHT_PERFECT_FWD(
0212     explicit rep_type,
0213     BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)
0214 
0215 #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
0216 
0217     rep_type(const rep_type& x):key(x.key),value_ptr(0){}
0218     rep_type(const value_type&):key(no_key_from_value_failure()){}
0219 
0220 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0221     rep_type(rep_type&& x):key(std::move(x.key)),value_ptr(0){}
0222     rep_type(value_type&&):key(no_key_from_value_failure()){}
0223 #endif
0224 
0225     ~rep_type()
0226     {
0227       if(value_ptr)value_ptr->~value_type();
0228     }
0229 
0230     operator const key_type&()const{return key;}
0231 
0232     operator const value_type&()const
0233     {
0234       /* This is always called after construct_value(),so we access spc
0235        * directly rather than through value_ptr to save us an indirection.
0236        */
0237 
0238       return *static_cast<value_type*>(spc_ptr());
0239     }
0240 
0241   private:
0242     friend struct regular_key_value;
0243 
0244     void* spc_ptr()const{return static_cast<void*>(&spc);}
0245 
0246     struct no_key_from_value_failure
0247     {
0248       BOOST_MPL_ASSERT_MSG(
0249         false,
0250         NO_KEY_FROM_VALUE_CONVERSION_PROVIDED,
0251         (key_type,value_type));
0252 
0253       operator const key_type&()const;
0254     };
0255 
0256     void construct_value()const
0257     {
0258       if(!value_ptr)value_ptr=new(spc_ptr())value_type(key);
0259     }
0260 
0261     key_type                                 key;
0262     mutable typename boost::aligned_storage<
0263       sizeof(value_type),
0264       boost::alignment_of<value_type>::value
0265     >::type                                  spc;
0266     mutable const value_type*                value_ptr;
0267   };
0268 
0269   static void construct_value(const rep_type& r)
0270   {
0271     r.construct_value();
0272   }
0273 
0274   /* copy_value() and move_value() can't really ever be called, provided to avoid
0275    * compile errors (it is the no_key_from_value_failure compile error we want to
0276    * appear in these cases).
0277    */
0278 
0279   static void copy_value(const rep_type&){}
0280 
0281 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0282   static void move_value(const rep_type&){}
0283 #endif
0284 };
0285 
0286 } /* namespace flyweights::detail */
0287 
0288 template<typename Key,typename Value,typename KeyFromValue>
0289 struct key_value:
0290   mpl::if_<
0291     is_same<KeyFromValue,no_key_from_value>,
0292     detail::regular_key_value<Key,Value>,
0293     detail::optimized_key_value<Key,Value,KeyFromValue>
0294   >::type
0295 {};
0296 
0297 } /* namespace flyweights */
0298 
0299 } /* namespace boost */
0300 
0301 #endif