|
1 | 1 | /* This file is part of YUView - The YUV player with advanced analytics toolset
|
2 | 2 | * <https://github.com/IENT/YUView>
|
3 |
| - * Copyright (C) 2015 Institut f�r Nachrichtentechnik, RWTH Aachen University, GERMANY |
| 3 | + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY |
4 | 4 | *
|
5 | 5 | * This program is free software; you can redistribute it and/or modify
|
6 | 6 | * it under the terms of the GNU General Public License as published by
|
|
32 | 32 |
|
33 | 33 | #pragma once
|
34 | 34 |
|
35 |
| -#include <common/Functions.h> |
36 |
| - |
37 |
| -#include <map> |
| 35 | +#include <algorithm> |
| 36 | +#include <array> |
| 37 | +#include <iterator> |
38 | 38 | #include <optional>
|
39 |
| -#include <stdexcept> |
40 |
| -#include <string> |
41 |
| -#include <vector> |
| 39 | +#include <string_view> |
42 | 40 |
|
43 |
| -/* This class implement mapping of "enum class" values to and from names (string). |
44 |
| - */ |
45 |
| -template <typename T> class EnumMapper |
46 |
| -{ |
47 |
| -public: |
48 |
| - enum class StringType |
49 |
| - { |
50 |
| - Name, |
51 |
| - Text, |
52 |
| - NameOrIndex |
53 |
| - }; |
54 |
| - struct Entry |
55 |
| - { |
56 |
| - Entry(T value, std::string name) : value(value), name(name) {} |
57 |
| - Entry(T value, std::string name, std::string text) : value(value), name(name), text(text) {} |
58 |
| - T value; |
59 |
| - std::string name; |
60 |
| - std::string text; |
61 |
| - }; |
| 41 | +#include "Functions.h" |
62 | 42 |
|
63 |
| - using EntryVector = std::vector<Entry>; |
| 43 | +using namespace std::string_view_literals; |
64 | 44 |
|
65 |
| - EnumMapper() = default; |
66 |
| - EnumMapper(const EntryVector &entryVector) : entryVector(entryVector){}; |
| 45 | +template <class ValueType, std::size_t N> struct EnumMapper |
| 46 | +{ |
| 47 | +public: |
| 48 | + using ValueNamePair = std::pair<ValueType, std::string_view>; |
| 49 | + using ItemArray = std::array<ValueType, N>; |
| 50 | + using ItemIterator = typename ItemArray::const_iterator; |
| 51 | + using NameArray = std::array<std::string_view, N>; |
| 52 | + using NameIterator = typename NameArray::const_iterator; |
67 | 53 |
|
68 |
| - std::optional<T> getValue(std::string name, StringType stringType = StringType::Name) const |
| 54 | + struct Iterator |
69 | 55 | {
|
70 |
| - if (stringType == StringType::NameOrIndex) |
71 |
| - if (auto index = functions::toUnsigned(name)) |
72 |
| - return this->at(*index); |
| 56 | + using iterator_category = std::forward_iterator_tag; |
| 57 | + using difference_type = int; |
| 58 | + using value_type = ValueNamePair; |
| 59 | + using pointer = ValueNamePair *; |
| 60 | + using reference = ValueNamePair &; |
73 | 61 |
|
74 |
| - for (const auto &entry : this->entryVector) |
| 62 | + Iterator(const ItemIterator itItem, const NameIterator itName) : itItem(itItem), itName(itName) |
75 | 63 | {
|
76 |
| - if ((stringType == StringType::Name && entry.name == name) || |
77 |
| - (stringType == StringType::NameOrIndex && entry.text == name) || |
78 |
| - (stringType == StringType::Text && entry.text == name)) |
79 |
| - return entry.value; |
| 64 | + this->valueNamePair.first = *itItem; |
| 65 | + this->valueNamePair.second = *itName; |
80 | 66 | }
|
81 |
| - return {}; |
82 |
| - } |
83 | 67 |
|
84 |
| - std::optional<T> getValueCaseInsensitive(std::string name, |
85 |
| - StringType stringType = StringType::Name) const |
86 |
| - { |
87 |
| - if (stringType == StringType::NameOrIndex) |
88 |
| - if (auto index = functions::toUnsigned(name)) |
89 |
| - return this->at(*index); |
| 68 | + ValueNamePair const &operator*() const { return this->valueNamePair; } |
| 69 | + ValueNamePair const *operator->() const { return &this->valueNamePair; } |
90 | 70 |
|
91 |
| - name = functions::toLower(name); |
92 |
| - for (const auto &entry : this->entryVector) |
| 71 | + Iterator &operator++() |
93 | 72 | {
|
94 |
| - if ((stringType == StringType::Name && functions::toLower(entry.name) == name) || |
95 |
| - (stringType == StringType::NameOrIndex && functions::toLower(entry.text) == name) || |
96 |
| - (stringType == StringType::Text && functions::toLower(entry.text) == name)) |
97 |
| - return entry.value; |
| 73 | + ++this->itItem; |
| 74 | + ++this->itName; |
| 75 | + this->valueNamePair.first = *this->itItem; |
| 76 | + this->valueNamePair.second = *this->itName; |
| 77 | + return *this; |
98 | 78 | }
|
99 |
| - return {}; |
100 |
| - } |
101 | 79 |
|
102 |
| - std::string getName(T value) const |
| 80 | + friend bool operator==(const Iterator &a, const Iterator &b) |
| 81 | + { |
| 82 | + return a.itItem == b.itItem && a.itName == b.itName; |
| 83 | + }; |
| 84 | + friend bool operator!=(const Iterator &a, const Iterator &b) |
| 85 | + { |
| 86 | + return a.itItem != b.itItem || a.itName != b.itName; |
| 87 | + }; |
| 88 | + |
| 89 | + private: |
| 90 | + ItemIterator itItem; |
| 91 | + NameIterator itName; |
| 92 | + ValueNamePair valueNamePair{}; |
| 93 | + }; |
| 94 | + |
| 95 | + Iterator begin() const { return Iterator(this->items.begin(), this->names.begin()); } |
| 96 | + Iterator end() const { return Iterator(this->items.end(), this->names.end()); } |
| 97 | + |
| 98 | + template <typename... Args> constexpr EnumMapper(Args... args) |
103 | 99 | {
|
104 |
| - for (const auto &entry : this->entryVector) |
105 |
| - if (entry.value == value) |
106 |
| - return entry.name; |
107 |
| - throw std::logic_error( |
108 |
| - "The given type T was not registered in the mapper. All possible enums must be mapped."); |
| 100 | + static_assert(sizeof...(Args) == N); |
| 101 | + this->addElementsRecursively(0, args...); |
109 | 102 | }
|
110 | 103 |
|
111 |
| - std::string getText(T value) const |
| 104 | + constexpr std::size_t size() const { return N; } |
| 105 | + |
| 106 | + constexpr std::string_view getName(const ValueType value) const |
112 | 107 | {
|
113 |
| - for (const auto &entry : this->entryVector) |
114 |
| - if (entry.value == value) |
115 |
| - return entry.text; |
116 |
| - throw std::logic_error( |
117 |
| - "The given type T was not registered in the mapper. All possible enums must be mapped."); |
| 108 | + const auto it = std::find(this->items.begin(), this->items.end(), value); |
| 109 | + if (it == this->items.end()) |
| 110 | + throw std::logic_error( |
| 111 | + "The given type T was not registered in the mapper. All possible enums must be mapped."); |
| 112 | + const auto index = std::distance(this->items.begin(), it); |
| 113 | + return this->names.at(index); |
118 | 114 | }
|
119 | 115 |
|
120 |
| - size_t indexOf(T value) const |
| 116 | + constexpr std::optional<ValueType> getValue(const std::string_view name) const |
121 | 117 | {
|
122 |
| - for (size_t i = 0; i < this->entryVector.size(); i++) |
123 |
| - if (this->entryVector.at(i).value == value) |
124 |
| - return i; |
125 |
| - throw std::logic_error( |
126 |
| - "The given type T was not registered in the mapper. All possible enums must be mapped."); |
| 118 | + const auto it = |
| 119 | + std::find_if(this->begin(), |
| 120 | + this->end(), |
| 121 | + [&name](const ValueNamePair &pair) { return pair.second == name; }); |
| 122 | + if (it == this->end()) |
| 123 | + return {}; |
| 124 | + |
| 125 | + return it->first; |
127 | 126 | }
|
128 | 127 |
|
129 |
| - std::optional<T> at(size_t index) const |
| 128 | + constexpr std::optional<ValueType> getValueCaseInsensitive(const std::string_view name) const |
130 | 129 | {
|
131 |
| - if (index >= this->entryVector.size()) |
| 130 | + const auto compareToNameLowercase = [&name](const std::string_view str) |
| 131 | + { |
| 132 | + if (name.length() != str.length()) |
| 133 | + return false; |
| 134 | + for (std::size_t i = 0; i < name.length(); ++i) |
| 135 | + { |
| 136 | + if (std::tolower(name.at(i)) != std::tolower(str.at(i))) |
| 137 | + return false; |
| 138 | + } |
| 139 | + return true; |
| 140 | + }; |
| 141 | + |
| 142 | + const auto it = std::find_if(this->names.begin(), this->names.end(), compareToNameLowercase); |
| 143 | + if (it == this->names.end()) |
132 | 144 | return {};
|
133 |
| - return this->entryVector.at(index).value; |
| 145 | + |
| 146 | + const auto index = std::distance(this->names.begin(), it); |
| 147 | + return this->items.at(index); |
134 | 148 | }
|
135 | 149 |
|
136 |
| - std::vector<T> getEnums() const |
| 150 | + std::optional<ValueType> getValueFromNameOrIndex(const std::string_view nameOrIndex) const |
137 | 151 | {
|
138 |
| - std::vector<T> m; |
139 |
| - for (const auto &entry : this->entryVector) |
140 |
| - m.push_back(entry.value); |
141 |
| - return m; |
| 152 | + if (auto index = functions::toUnsigned(nameOrIndex)) |
| 153 | + if (*index < N) |
| 154 | + return this->items.at(*index); |
| 155 | + |
| 156 | + return this->getValue(nameOrIndex); |
142 | 157 | }
|
143 | 158 |
|
144 |
| - std::vector<std::string> getNames() const |
| 159 | + constexpr size_t indexOf(const ValueType value) const |
145 | 160 | {
|
146 |
| - std::vector<std::string> l; |
147 |
| - for (const auto &entry : this->entryVector) |
148 |
| - l.push_back(entry.name); |
149 |
| - return l; |
| 161 | + const auto it = std::find(this->items.begin(), this->items.end(), value); |
| 162 | + if (it == this->items.end()) |
| 163 | + throw std::logic_error( |
| 164 | + "The given type T was not registered in the mapper. All possible enums must be mapped."); |
| 165 | + |
| 166 | + const auto index = std::distance(this->items.begin(), it); |
| 167 | + return index; |
150 | 168 | }
|
151 | 169 |
|
152 |
| - std::vector<std::string> getTextEntries() const |
| 170 | + constexpr std::optional<ValueType> at(const size_t index) const |
153 | 171 | {
|
154 |
| - std::vector<std::string> l; |
155 |
| - for (const auto &entry : this->entryVector) |
156 |
| - l.push_back(entry.text); |
157 |
| - return l; |
| 172 | + if (index >= N) |
| 173 | + return {}; |
| 174 | + return this->items.at(index); |
158 | 175 | }
|
159 | 176 |
|
160 |
| - size_t size() const { return this->entryVector.size(); } |
161 |
| - |
162 |
| - const EntryVector &entries() const { return this->entryVector; } |
| 177 | + constexpr const ItemArray &getValues() const { return this->items; } |
| 178 | + constexpr const NameArray &getNames() const { return this->names; } |
163 | 179 |
|
164 | 180 | private:
|
165 |
| - EntryVector entryVector; |
| 181 | + constexpr void addElementsRecursively(const std::size_t) {}; |
| 182 | + |
| 183 | + template <typename ArgumentType, typename... Args> |
| 184 | + constexpr void addElementsRecursively(const std::size_t index, ArgumentType first, Args... args) |
| 185 | + { |
| 186 | + static_assert(std::is_same<ValueNamePair, ArgumentType>()); |
| 187 | + |
| 188 | + const auto [value, name] = first; |
| 189 | + this->items[index] = value; |
| 190 | + this->names[index] = name; |
| 191 | + |
| 192 | + addElementsRecursively(index + 1, args...); |
| 193 | + } |
| 194 | + |
| 195 | + ItemArray items{}; |
| 196 | + NameArray names{}; |
166 | 197 | };
|
0 commit comments