test/common/cache.hpp
| 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 | 147428 | constexpr size_t hash_combine(size_t lhs, size_t rhs) noexcept { | |
| 15 | 147428 | 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 | 147428 | static size_t combine(const Tuple& tuple) noexcept { | |
| 23 | using EType = std::tuple_element_t<Index, Tuple>; | ||
| 24 | 147428 | return hash_combine( | |
| 25 |
3/6✓ Branch 0 taken 21831 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21831 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21831 times.
✗ Branch 5 not taken.
|
147428 | std::hash<EType>{}(std::get<Index>(tuple)), // hash of current element |
| 26 | 147428 | 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 | 27295 | static size_t combine(const Tuple& tuple) noexcept { | |
| 35 | using EType = std::tuple_element_t<0, Tuple>; | ||
| 36 |
2/4✓ Branch 0 taken 26649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 646 times.
✗ Branch 3 not taken.
|
27295 | return std::hash<EType>{}(std::get<0>(tuple)); |
| 37 | } | ||
| 38 | }; | ||
| 39 | } // namespace impl | ||
| 40 | |||
| 41 | struct TupleHash { | ||
| 42 | template <typename... Args> | ||
| 43 | 27295 | std::size_t operator()(const std::tuple<Args...>& tuple) const noexcept { | |
| 44 | 27295 | 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 | 20320 | static ReferenceGenerator& getRG() { | |
| 67 |
6/8✓ Branch 0 taken 10 times.
✓ Branch 1 taken 20118 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 190 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
|
20320 | static ReferenceGenerator rg; |
| 68 | 20320 | return rg; | |
| 69 | } | ||
| 70 | |||
| 71 | 20320 | const V& get_test_reference(const K& test_id) { | |
| 72 |
6/10✓ Branch 0 taken 18568 times.
✓ Branch 1 taken 1560 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18568 times.
✓ Branch 4 taken 1560 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 192 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 192 times.
|
38888 | if (const auto itr = m_data.find(test_id); itr != end(m_data)) { |
| 73 | 18568 | return itr->second; | |
| 74 | } | ||
| 75 | |||
| 76 |
2/4✓ Branch 0 taken 1560 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
|
1752 | return m_data[test_id] = generate_reference(test_id); |
| 77 | 20320 | } | |
| 78 | |||
| 79 | private: | ||
| 80 | 18 | 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 | 20320 | inline const V& getV(const K& k) { | |
| 92 | 20320 | auto& rg = ReferenceGenerator<K, V>::getRG(); | |
| 93 | 40640 | return rg.get_test_reference(k); | |
| 94 | 20320 | } | |
| 95 | |||
| 96 | }; // namespace kai::test | ||
| 97 |