## include/boost/regex/v5/object_cache.hpp

95.5% Lines (42/44) 100.0% List of functions (6/6)
object_cache.hpp
f(x) Functions (6)
Function Calls Lines Blocks
boost::object_cache<boost::re_detail_600::cpp_regex_traits_base<char>, boost::re_detail_600::cpp_regex_traits_implementation<char> >::get(boost::re_detail_600::cpp_regex_traits_base<char> const&, unsigned long) :67 28745x 80.0% 100.0% boost::object_cache<boost::re_detail_600::cpp_regex_traits_base<wchar_t>, boost::re_detail_600::cpp_regex_traits_implementation<wchar_t> >::get(boost::re_detail_600::cpp_regex_traits_base<wchar_t> const&, unsigned long) :67 28787x 100.0% 100.0% boost::object_cache<int, test_object>::get(int const&, unsigned long) :67 159x 100.0% 78.0% boost::object_cache<boost::re_detail_600::cpp_regex_traits_base<char>, boost::re_detail_600::cpp_regex_traits_implementation<char> >::do_get(boost::re_detail_600::cpp_regex_traits_base<char> const&, unsigned long) :82 28745x 43.6% 40.0% boost::object_cache<boost::re_detail_600::cpp_regex_traits_base<wchar_t>, boost::re_detail_600::cpp_regex_traits_implementation<wchar_t> >::do_get(boost::re_detail_600::cpp_regex_traits_base<wchar_t> const&, unsigned long) :82 28787x 43.6% 40.0% boost::object_cache<int, test_object>::do_get(int const&, unsigned long) :82 159x 97.4% 78.0%

Line | TLA | Hits | Source Code
--- | --- | --- | ---
1 |  |  | /*
2 |  |  | *
3 |  |  | * Copyright (c) 2004
4 |  |  | * John Maddock
5 |  |  | *
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)
9 |  |  | *
10 |  |  | */
11 |  |  |
12 |  |  | /*
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.
17 |  |  | */
18 |  |  |
19 |  |  | #ifndef BOOST_REGEX_OBJECT_CACHE_HPP
20 |  |  | #define BOOST_REGEX_OBJECT_CACHE_HPP
21 |  |  |
22 |  |  | #include <boost/regex/config.hpp>
23 |  |  | #ifndef BOOST_REGEX_AS_MODULE
24 |  |  | #include <memory>
25 |  |  | #include <map>
26 |  |  | #include <list>
27 |  |  | #include <stdexcept>
28 |  |  | #include <string>
29 |  |  | #ifdef BOOST_HAS_THREADS
30 |  |  | #include <mutex>
31 |  |  | #endif
32 |  |  | #endif
33 |  |  |
34 |  |  | namespace boost{
35 |  |  |
36 |  |  | template <class Key, class Object>
37 |  |  | class object_cache
38 |  |  | {
39 |  |  | public:
40 |  |  | typedef std::pair< ::std::shared_ptr<Object const>, Key const*> value_type;
41 |  |  | typedef std::list<value_type> list_type;
42 |  |  | typedef typename list_type::iterator list_iterator;
43 |  |  | typedef std::map<Key, list_iterator> map_type;
44 |  |  | typedef typename map_type::iterator map_iterator;
45 |  |  | typedef typename list_type::size_type size_type;
46 |  |  | static std::shared_ptr<Object const> get(const Key& k, size_type l_max_cache_size);
47 |  |  |
48 |  |  | private:
49 |  |  | static std::shared_ptr<Object const> do_get(const Key& k, size_type l_max_cache_size);
50 |  |  |
51 |  |  | struct data
52 |  |  | {
53 |  |  | list_type cont;
54 |  |  | map_type index;
55 |  |  | };
56 |  |  |
57 |  |  | // Needed by compilers not implementing the resolution to DR45. For reference,
58 |  |  | // see http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45.
59 |  |  | friend struct data;
60 |  |  | };
61 |  |  |
62 |  |  | #ifdef BOOST_REGEX_MSVC
63 |  |  | #pragma warning(push)
64 |  |  | #pragma warning(disable: 4702)
65 |  |  | #endif
66 |  |  | template <class Key, class Object>
67 |  | 57691x | std::shared_ptr<Object const> object_cache<Key, Object>::get(const Key& k, size_type l_max_cache_size)
68 |  |  | {
69 |  |  | #ifdef BOOST_HAS_THREADS
70 |  |  | static std::mutex mut;
71 |  | 57691x | std::lock_guard<std::mutex> l(mut);
72 |  | 110594x | return do_get(k, l_max_cache_size);
73 |  |  | #else
74 |  | ✗ | return do_get(k, l_max_cache_size);
75 |  |  | #endif
76 |  | 57691x | }
77 |  |  | #ifdef BOOST_REGEX_MSVC
78 |  |  | #pragma warning(pop)
79 |  |  | #endif
80 |  |  |
81 |  |  | template <class Key, class Object>
82 |  | 57691x | std::shared_ptr<Object const> object_cache<Key, Object>::do_get(const Key& k, size_type l_max_cache_size)
83 |  |  | {
84 |  |  | typedef typename object_cache<Key, Object>::data object_data;
85 |  |  | typedef typename map_type::size_type map_size_type;
86 |  | 57691x | static object_data s_data;
87 |  |  |
88 |  |  | //
89 |  |  | // see if the object is already in the cache:
90 |  |  | //
91 |  | 57691x | map_iterator mpos = s_data.index.find(k);
92 |  | 57691x | if(mpos != s_data.index.end())
93 |  |  | {
94 |  |  | //
95 |  |  | // Eureka!
96 |  |  | // We have a cached item, bump it up the list and return it:
97 |  |  | //
98 |  | 57627x | if(--(s_data.cont.end()) != mpos->second)
99 |  |  | {
100 |  |  | // splice out the item we want to move:
101 |  | 69x | list_type temp;
102 |  | 69x | temp.splice(temp.end(), s_data.cont, mpos->second);
103 |  |  | // and now place it at the end of the list:
104 |  | 69x | s_data.cont.splice(s_data.cont.end(), temp, temp.begin());
105 |  | 69x | BOOST_REGEX_ASSERT(*(s_data.cont.back().second) == k);
106 |  |  | // update index with new position:
107 |  | 69x | mpos->second = --(s_data.cont.end());
108 |  | 69x | BOOST_REGEX_ASSERT(&(mpos->first) == mpos->second->second);
109 |  | 69x | BOOST_REGEX_ASSERT(&(mpos->first) == s_data.cont.back().second);
110 |  | 69x | }
111 |  | 57627x | return s_data.cont.back().first;
112 |  |  | }
113 |  |  | //
114 |  |  | // if we get here then the item is not in the cache,
115 |  |  | // so create it:
116 |  |  | //
117 |  | 64x | std::shared_ptr<Object const> result(new Object(k));
118 |  |  | //
119 |  |  | // Add it to the list, and index it:
120 |  |  | //
121 |  | 64x | s_data.cont.push_back(value_type(result, static_cast<Key const*>(0)));
122 |  | 64x | s_data.index.insert(std::make_pair(k, --(s_data.cont.end())));
123 |  | 64x | s_data.cont.back().second = &(s_data.index.find(k)->first);
124 |  | 64x | map_size_type s = s_data.index.size();
125 |  | 64x | BOOST_REGEX_ASSERT(s_data.index[k]->first.get() == result.get());
126 |  | 64x | BOOST_REGEX_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second);
127 |  | 64x | BOOST_REGEX_ASSERT(s_data.index.find(k)->first == k);
128 |  | 64x | if(s > l_max_cache_size)
129 |  |  | {
130 |  |  | //
131 |  |  | // We have too many items in the list, so we need to start
132 |  |  | // popping them off the back of the list, but only if they're
133 |  |  | // being held uniquely by us:
134 |  |  | //
135 |  | 15x | list_iterator pos = s_data.cont.begin();
136 |  | 15x | list_iterator last = s_data.cont.end();
137 |  | 30x | while((pos != last) && (s > l_max_cache_size))
138 |  |  | {
139 |  | 15x | if(pos->first.use_count() == 1)
140 |  |  | {
141 |  | 15x | list_iterator condemmed(pos);
142 |  | 15x | ++pos;
143 |  |  | // now remove the items from our containers,
144 |  |  | // then order has to be as follows:
145 |  | 15x | BOOST_REGEX_ASSERT(s_data.index.find(*(condemmed->second)) != s_data.index.end());
146 |  | 15x | s_data.index.erase(*(condemmed->second));
147 |  | 15x | s_data.cont.erase(condemmed);
148 |  | 15x | --s;
149 |  |  | }
150 |  |  | else
151 |  | ✗ | ++pos;
152 |  |  | }
153 |  | 15x | BOOST_REGEX_ASSERT(s_data.index[k]->first.get() == result.get());
154 |  | 15x | BOOST_REGEX_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second);
155 |  | 15x | BOOST_REGEX_ASSERT(s_data.index.find(k)->first == k);
156 |  |  | }
157 |  | 64x | return result;
158 |  | 64x | }
159 |  |  |
160 |  |  | }
161 |  |  |
162 |  |  | #endif
163 |  |  |