Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com> | ||
3 | // | ||
4 | // SPDX-License-Identifier: Apache-2.0 | ||
5 | // | ||
6 | |||
7 | #include <tuple> | ||
8 | #include <unordered_map> | ||
9 | |||
10 | namespace kai::test { | ||
11 | |||
12 | namespace impl { | ||
13 | /// Naive combination of two hash values | ||
14 | 3729 | constexpr size_t hash_combine(size_t lhs, size_t rhs) noexcept { | |
15 | 3729 | return lhs ^ (rhs << 3); | |
16 | } | ||
17 | |||
18 | /// Tuple hash recursive case, combines hash of Ith hash with Ith - 1 hash. | ||
19 | /// Defaults to last element in tuple | ||
20 | template <typename Tuple, std::size_t Index = std::tuple_size<Tuple>::value - 1> | ||
21 | struct TupleHash { | ||
22 | 3729 | static size_t combine(const Tuple& tuple) noexcept { | |
23 | using EType = std::tuple_element_t<Index, Tuple>; | ||
24 | 3729 | return hash_combine( | |
25 |
3/6✓ Branch 0 taken 1243 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1243 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1243 times.
✗ Branch 5 not taken.
|
3729 | std::hash<EType>{}(std::get<Index>(tuple)), // hash of current element |
26 | 3729 | TupleHash<Tuple, Index - 1>::combine(tuple) // hash of previous elements | |
27 | ); | ||
28 | } | ||
29 | }; | ||
30 | |||
31 | /// TupleHash base case, returns hash of first value | ||
32 | template <typename Tuple> | ||
33 | struct TupleHash<Tuple, 0> { | ||
34 | 1243 | static size_t combine(const Tuple& tuple) noexcept { | |
35 | using EType = std::tuple_element_t<0, Tuple>; | ||
36 |
1/2✓ Branch 0 taken 1243 times.
✗ Branch 1 not taken.
|
1243 | return std::hash<EType>{}(std::get<0>(tuple)); |
37 | } | ||
38 | }; | ||
39 | } // namespace impl | ||
40 | |||
41 | struct TupleHash { | ||
42 | template <typename... Args> | ||
43 | 1243 | std::size_t operator()(const std::tuple<Args...>& tuple) const noexcept { | |
44 | 1243 | return impl::TupleHash<std::tuple<Args...>>::combine(tuple); | |
45 | } | ||
46 | }; | ||
47 | |||
48 | /// Cached reference cache | ||
49 | /// | ||
50 | /// The user need to specialize and implement the private `generate_reference()` function, which | ||
51 | /// will then be used by the cache mechanism to generate cached reference data | ||
52 | /// | ||
53 | /// template <> | ||
54 | /// CacheData ReferenceGenerator<YourTestID, YourTestData>::generate_reference(const YourTestID& k) { | ||
55 | /// ... | ||
56 | /// } | ||
57 | /// | ||
58 | /// And then use the `getV()` helper function to retrieve test reference data | ||
59 | /// | ||
60 | /// const auto& test_data = getV<YourTestID, YourTestData>(test_id); | ||
61 | /// | ||
62 | /// Notice that current implementation can be quite memory intensive, but the positive tradeoff | ||
63 | /// is its ease of use | ||
64 | template <typename K, typename V> | ||
65 | struct ReferenceGenerator final { | ||
66 | 1232 | static ReferenceGenerator& getRG() { | |
67 |
3/4✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1231 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
|
1232 | static ReferenceGenerator rg; |
68 | 1232 | return rg; | |
69 | } | ||
70 | |||
71 | 1232 | const V& get_test_reference(const K& test_id) { | |
72 |
4/5✓ Branch 0 taken 1221 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1221 times.
✓ Branch 4 taken 11 times.
|
2453 | if (const auto itr = m_data.find(test_id); itr != end(m_data)) { |
73 | 1221 | return itr->second; | |
74 | } | ||
75 | |||
76 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | return m_data[test_id] = generate_reference(test_id); |
77 | 1232 | } | |
78 | |||
79 | private: | ||
80 | 2 | ReferenceGenerator() = default; | |
81 | |||
82 | std::unordered_map<K, V, TupleHash> m_data; | ||
83 | |||
84 | V generate_reference(const K& test_id); | ||
85 | }; | ||
86 | |||
87 | /// Main accessor function for retrieving reference test values from test identifier. | ||
88 | /// | ||
89 | /// This can also be used as a shim between test data creation and usage | ||
90 | template <typename K, typename V, typename RG = ReferenceGenerator<K, V>> | ||
91 | 1232 | inline const V& getV(const K& k) { | |
92 | 1232 | auto& rg = ReferenceGenerator<K, V>::getRG(); | |
93 | 2464 | return rg.get_test_reference(k); | |
94 | 1232 | } | |
95 | |||
96 | }; // namespace kai::test | ||
97 |