6 * Use, modification and distribution are subject to the
7 * Boost Software License, Version 1.0. (See accompanying file
8 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
13 * LOCATION: see http://www.boost.org for most recent version.
14 * FILE object_cache.hpp
15 * VERSION see <boost/version.hpp>
16 * DESCRIPTION: Implements a generic object cache.
19 #ifndef BOOST_REGEX_OBJECT_CACHE_HPP
20 #define BOOST_REGEX_OBJECT_CACHE_HPP
26 #include <boost/config.hpp>
27 #include <boost/shared_ptr.hpp>
28 #ifdef BOOST_HAS_THREADS
29 #include <boost/regex/pending/static_mutex.hpp>
34 template <class Key
, class Object
>
38 typedef std::pair
< ::boost::shared_ptr
<Object
const>, Key
const*> value_type
;
39 typedef std::list
<value_type
> list_type
;
40 typedef typename
list_type::iterator list_iterator
;
41 typedef std::map
<Key
, list_iterator
> map_type
;
42 typedef typename
map_type::iterator map_iterator
;
43 typedef typename
list_type::size_type size_type
;
44 static boost::shared_ptr
<Object
const> get(const Key
& k
, size_type max_cache_size
);
47 static boost::shared_ptr
<Object
const> do_get(const Key
& k
, size_type max_cache_size
);
55 // Needed by compilers not implementing the resolution to DR45. For reference,
56 // see http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45.
60 template <class Key
, class Object
>
61 boost::shared_ptr
<Object
const> object_cache
<Key
, Object
>::get(const Key
& k
, size_type max_cache_size
)
63 #ifdef BOOST_HAS_THREADS
64 static boost::static_mutex mut
= BOOST_STATIC_MUTEX_INIT
;
66 boost::static_mutex::scoped_lock
l(mut
);
69 return do_get(k
, max_cache_size
);
72 // what do we do if the lock fails?
73 // for now just throw, but we should never really get here...
75 ::boost::throw_exception(std::runtime_error("Error in thread safety code: could not acquire a lock"));
76 return boost::shared_ptr
<Object
>();
78 return do_get(k
, max_cache_size
);
82 template <class Key
, class Object
>
83 boost::shared_ptr
<Object
const> object_cache
<Key
, Object
>::do_get(const Key
& k
, size_type max_cache_size
)
85 typedef typename object_cache
<Key
, Object
>::data object_data
;
86 typedef typename
map_type::size_type map_size_type
;
87 static object_data s_data
;
90 // see if the object is already in the cache:
92 map_iterator mpos
= s_data
.index
.find(k
);
93 if(mpos
!= s_data
.index
.end())
97 // We have a cached item, bump it up the list and return it:
99 if(--(s_data
.cont
.end()) != mpos
->second
)
101 // splice out the item we want to move:
103 temp
.splice(temp
.end(), s_data
.cont
, mpos
->second
);
104 // and now place it at the end of the list:
105 s_data
.cont
.splice(s_data
.cont
.end(), temp
, temp
.begin());
106 BOOST_ASSERT(*(s_data
.cont
.back().second
) == k
);
107 // update index with new position:
108 mpos
->second
= --(s_data
.cont
.end());
109 BOOST_ASSERT(&(mpos
->first
) == mpos
->second
->second
);
110 BOOST_ASSERT(&(mpos
->first
) == s_data
.cont
.back().second
);
112 return s_data
.cont
.back().first
;
115 // if we get here then the item is not in the cache,
118 boost::shared_ptr
<Object
const> result(new Object(k
));
120 // Add it to the list, and index it:
122 s_data
.cont
.push_back(value_type(result
, static_cast<Key
const*>(0)));
123 s_data
.index
.insert(std::make_pair(k
, --(s_data
.cont
.end())));
124 s_data
.cont
.back().second
= &(s_data
.index
.find(k
)->first
);
125 map_size_type s
= s_data
.index
.size();
126 BOOST_ASSERT(s_data
.index
[k
]->first
.get() == result
.get());
127 BOOST_ASSERT(&(s_data
.index
.find(k
)->first
) == s_data
.cont
.back().second
);
128 BOOST_ASSERT(s_data
.index
.find(k
)->first
== k
);
129 if(s
> max_cache_size
)
132 // We have too many items in the list, so we need to start
133 // popping them off the back of the list, but only if they're
134 // being held uniquely by us:
136 list_iterator pos
= s_data
.cont
.begin();
137 list_iterator last
= s_data
.cont
.end();
138 while((pos
!= last
) && (s
> max_cache_size
))
140 if(pos
->first
.unique())
142 list_iterator
condemmed(pos
);
144 // now remove the items from our containers,
145 // then order has to be as follows:
146 BOOST_ASSERT(s_data
.index
.find(*(condemmed
->second
)) != s_data
.index
.end());
147 s_data
.index
.erase(*(condemmed
->second
));
148 s_data
.cont
.erase(condemmed
);
154 BOOST_ASSERT(s_data
.index
[k
]->first
.get() == result
.get());
155 BOOST_ASSERT(&(s_data
.index
.find(k
)->first
) == s_data
.cont
.back().second
);
156 BOOST_ASSERT(s_data
.index
.find(k
)->first
== k
);