1 /*
2     Copyright (c) 2005-2021 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 #ifndef __TBB_test_common_concurrent_lru_cache_common
18 #define __TBB_test_common_concurrent_lru_cache_common
19 
20 
21 #include "test.h"
22 #include <tbb/concurrent_lru_cache.h>
23 
24 //-----------------------------------------------------------------------------
25 // Concurrent LRU Cache Tests: Cache Helpers
26 //-----------------------------------------------------------------------------
27 
28 namespace concurrent_lru_cache_helpers {
29 
30     // call counter
31 
32     template<std::size_t id>
33     struct tag{};
34 
35     template<typename Tag, typename Type>
36     struct call_counter {
37         static int calls;
38 
39         static Type call(Type t) {
40             ++calls;
41             return t;
42         }
43     };
44 
45     template<typename Tag, typename Type>
46     int call_counter<Tag, Type>::calls = 0;
47 
48     // cloner
49 
50     template<typename ValueType>
51     struct cloner {
52         ValueType& my_ref_to_original;
53 
54         cloner(ValueType& ref_to_original) : my_ref_to_original(ref_to_original) {}
55 
56         template<typename KeyType>
57         ValueType operator()(KeyType) const { return my_ref_to_original; }
58     };
59 
60     // map searcher
61 
62     template <typename KeyType, typename ValueType>
63     struct map_searcher {
64         using map_type = std::map<KeyType, ValueType>;
65         using map_iter = typename map_type::iterator;
66 
67         map_type& my_map_ref;
68 
69         map_searcher(map_type& map_ref) : my_map_ref(map_ref) {}
70 
71         ValueType& operator()(KeyType k) {
72             map_iter it = my_map_ref.find(k);
73             if (it == my_map_ref.end())
74                 it = my_map_ref.insert(it, std::make_pair(k, ValueType()));
75 
76             return it->second;
77         }
78     };
79 
80     // array searcher
81 
82     template<typename key_type, typename value_type, std::size_t array_size>
83     struct array_searcher {
84         using array_type = value_type[array_size];
85 
86         array_type const& my_array_ref;
87 
88         array_searcher(array_type const& array_ref) : my_array_ref(array_ref) {}
89 
90         const value_type& operator()(key_type k) const {
91             std::size_t index = k;
92             REQUIRE_MESSAGE(k < array_size, "incorrect test setup");
93             return my_array_ref[index];
94         }
95     };
96 
97     // instance counter
98 
99     template<typename CounterType = std::size_t>
100     struct instance_counter {
101         CounterType* my_p_count;
102 
103         instance_counter() : my_p_count(new CounterType) {
104             *my_p_count = 1;
105         }
106 
107         instance_counter(instance_counter const& other) : my_p_count(other.my_p_count) {
108             ++(*my_p_count);
109         }
110 
111         instance_counter& operator=(instance_counter other) {
112             std::swap(this->my_p_count, other.my_p_count);
113             return *this;
114         }
115 
116         ~instance_counter() {
117             if (! --(*my_p_count))
118                 delete(my_p_count);
119         }
120 
121         std::size_t instances_count() const { return *my_p_count; }
122     };
123 
124     using instance_serial_counter = instance_counter<>;
125     using instance_concurrent_counter = instance_counter<std::atomic<std::size_t>>;
126 };
127 
128 //-----------------------------------------------------------------------------
129 // Concurrent LRU Cache Tests: Cache Presets
130 //-----------------------------------------------------------------------------
131 
132 namespace concurrent_lru_cache_presets {
133 
134     namespace helpers = concurrent_lru_cache_helpers;
135 
136     // base preset with common typedefs and fields
137 
138     template<typename... CacheTypes>
139     struct preset_base {
140         using cache_type = tbb::concurrent_lru_cache<CacheTypes...>;
141         using handle_type = typename cache_type::handle;
142 
143         preset_base() {}
144         preset_base(const preset_base&) = delete;
145         preset_base(preset_base&&) = delete;
146         preset_base& operator=(const preset_base&) = delete;
147         preset_base& operator=(preset_base&&) = delete;
148     };
149 
150     // default preset
151 
152     template<typename Key, typename Value>
153     struct preset_default : preset_base<Key, Value> {
154         using cache_type = typename preset_base<Key, Value>::cache_type;
155         using handle_type = typename cache_type::handle;
156         using callback_type = typename cache_type::value_function_type;
157 
158         const std::size_t number_of_lru_history_items;
159         cache_type cache;
160 
161         preset_default(callback_type callback, std::size_t history_items) :
162             number_of_lru_history_items(history_items),
163             cache(callback, number_of_lru_history_items) {};
164     };
165 
166     // preset1
167 
168     struct preset1 : preset_base<std::string, std::string> {
169         const std::size_t number_of_lru_history_items;
170         cache_type cache;
171         handle_type default_ctor_check;
172 
173         static std::string callback(std::string key) { return key; }
174 
175         preset1() :
176             number_of_lru_history_items(1),
177             cache(&callback, number_of_lru_history_items) {};
178     };
179 
180     // preset for call counting
181 
182     template<std::size_t tag_id>
183     struct preset_call_count : preset_base<int, int> {
184         using cache_miss_tag = helpers::tag<tag_id>;
185         using counter_type = helpers::call_counter<cache_miss_tag, int>;
186 
187         const std::size_t number_of_lru_history_items;
188         cache_type cache;
189 
190         preset_call_count() :
191             number_of_lru_history_items(8),
192             cache(&counter_type::call, number_of_lru_history_items) {}
193     };
194 
195     // preset for instance counting
196 
197     struct preset_instance_count : preset_base<
198         std::size_t, helpers::instance_serial_counter,
199         helpers::cloner<helpers::instance_serial_counter>> {
200 
201         using cloner_type = helpers::cloner<helpers::instance_serial_counter>;
202 
203         helpers::instance_serial_counter source;
204         cloner_type cloner;
205         const std::size_t number_of_lru_history_items;
206         cache_type cache;
207 
208         preset_instance_count() :
209             cloner(source),
210             number_of_lru_history_items(8),
211             cache(cloner, number_of_lru_history_items) {}
212     };
213 
214     // preset for instance counting with external map
215 
216     struct preset_map_instance_count : preset_base<
217         std::size_t, helpers::instance_serial_counter,
218         helpers::map_searcher<std::size_t, helpers::instance_serial_counter>> {
219 
220         using map_searcher_type = helpers::map_searcher<std::size_t, helpers::instance_serial_counter>;
221         using objects_map_type = map_searcher_type::map_type;
222 
223         static const std::size_t number_of_lru_history_items;
224         map_searcher_type::map_type objects_map;
225         cache_type cache;
226 
227         preset_map_instance_count() :
228             cache(map_searcher_type(objects_map), number_of_lru_history_items) {}
229 
230         bool is_evicted(std::size_t key) {
231             objects_map_type::iterator it = objects_map.find(key);
232 
233             REQUIRE_MESSAGE(
234                 it != objects_map.end(),
235                 "no value for key - error in test logic ?");
236 
237             return it->second.instances_count() == 1;
238         }
239 
240         void fill_up_cache(std::size_t lower_bound, std::size_t upper_bound) {
241             for (std::size_t i = lower_bound; i < upper_bound; ++i)
242                 cache[i];
243         }
244     };
245 
246     const std::size_t preset_map_instance_count::number_of_lru_history_items = 8;
247 };
248 
249 #endif // __TBB_test_common_concurrent_lru_cache_common
250