FINAL CUT
fkey_hashmap.h
1 /***********************************************************************
2 * fkey_hashmap.h - Key sequence hash map access *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2015-2026 Markus Gans *
7 * *
8 * FINAL CUT is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as *
10 * published by the Free Software Foundation; either version 3 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * FINAL CUT is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this program. If not, see *
20 * <http://www.gnu.org/licenses/>. *
21 ***********************************************************************/
22 
23 #ifndef FKEYHASHMAP_H
24 #define FKEYHASHMAP_H
25 
26 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
27  #error "Only <final/final.h> can be included directly."
28 #endif
29 
30 #include <algorithm>
31 #include <memory>
32 #include <string>
33 #include <unordered_map>
34 
35 #include "final/fc.h"
36 #include "final/input/fkey_map.h"
37 
38 namespace finalcut
39 {
40 
41 namespace fkeyhashmap
42 {
43 
44 namespace internal
45 {
46 
47 struct Const
48 {
49  static constexpr auto getMaxHashSize() noexcept -> std::size_t
50  {
51  #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a::value_type))
52  constexpr std::size_t key_map_size = ARRAY_SIZE(FKeyMap::KeyMapType);
53  constexpr std::size_t keycap_map_size = ARRAY_SIZE(FKeyMap::KeyCapMapType);
54  #undef ARRAY_SIZE
55  return std::max(key_map_size, keycap_map_size) * 2;
56  }
57 };
58 
59 //----------------------------------------------------------------------
60 template <typename BufferT>
62 {
63  constexpr KeySequence (const char* s, uInt8 l)
64  : string(s)
65  , length(l)
66  { }
67 
68  constexpr explicit KeySequence (const BufferT& buf)
69  : buffer(&buf)
70  { }
71 
72  const char* string{nullptr};
73  const uInt8 length{0};
74  const BufferT* buffer{nullptr};
75 };
76 
77 //----------------------------------------------------------------------
78 template <typename IterT>
79 constexpr auto hash_function (IterT iter, const IterT end) -> std::size_t
80 {
81  // FNV-1a hash
82  constexpr std::size_t FNV_OFFSET_BASIS = \
83  ( std::numeric_limits<std::size_t>::digits == 64 )
84  ? 14695981039346656037ULL
85  : 2166136261UL;
86 
87  constexpr std::size_t FNV_PRIME = \
88  ( std::numeric_limits<unsigned int>::digits == 64 )
89  ? 1099511628211ULL
90  : 16777619UL;
91 
92  std::size_t hash = FNV_OFFSET_BASIS;
93  std::for_each ( iter
94  , end
95  , [&hash] (auto item) noexcept
96  {
97  hash ^= static_cast<std::size_t>(item);
98  hash *= FNV_PRIME;
99  }
100  );
101  return hash & (Const::getMaxHashSize() - 1);
102 }
103 
104 //----------------------------------------------------------------------
105 template <typename BufferT>
106 constexpr auto hash_function (const BufferT& buf) -> std::size_t
107 {
108  return hash_function (std::begin(buf), std::end(buf));
109 }
110 
111 //----------------------------------------------------------------------
112 template <typename BufferT>
114 {
115  auto operator () (const KeySequence<BufferT>& key) const noexcept -> std::size_t
116  {
117  if ( key.string && ! key.buffer )
118  return hash_function (key.string, std::next(key.string, key.length));
119 
120  if ( key.buffer )
121  return hash_function (*key.buffer);
122 
123  static constexpr char unknown_key[] = "unknown";
124  return hash_function(unknown_key, std::next(unknown_key, sizeof(unknown_key) - 1));
125  }
126 };
127 
128 //----------------------------------------------------------------------
129 template <typename BufferT>
131 {
132  auto operator () ( const KeySequence<BufferT>& lhs
133  , const KeySequence<BufferT>& rhs) const noexcept -> bool
134  {
135  if ( lhs.string && ! lhs.buffer && rhs.string && ! rhs.buffer )
136  {
137  return lhs.length == rhs.length
138  && std::memcmp(lhs.string, rhs.string, rhs.length) == 0;
139  }
140 
141  if ( ! lhs.string && lhs.buffer && rhs.string && ! rhs.buffer )
142  {
143  return lhs.buffer->getSize() == rhs.length
144  && lhs.buffer->strncmp_front(rhs.string, rhs.length);
145  }
146 
147  if ( lhs.string && ! lhs.buffer && ! rhs.string && rhs.buffer )
148  {
149  return lhs.length == rhs.buffer->getSize()
150  && rhs.buffer->strncmp_front(lhs.string, lhs.length);
151  }
152 
153  return false;
154  }
155 };
156 
157 //----------------------------------------------------------------------
158 // Using-declaration
159 template <typename BufferT>
160 using HashMap = std::unordered_map<KeySequence<BufferT>
161  , FKey
164 
165 //----------------------------------------------------------------------
166 template <typename BufferT>
167 auto createKeyCapMap() -> HashMap<BufferT>
168 {
169  const auto& fkey_cap_table = FKeyMap::getKeyCapMap();
170  HashMap<BufferT> fkey_cap_map;
171 
172  // Reserve more space (1.25×) to avoid rehashing during construction
173  fkey_cap_map.reserve((fkey_cap_table.size() * 5) / 4); // ⁵⁄₄ = 1.25
174 
175  for (const auto& item : fkey_cap_table)
176  if ( item.string && item.length != 0 )
177  fkey_cap_map[{item.string, item.length}] = item.num;
178 
179  return fkey_cap_map;
180 }
181 
182 //----------------------------------------------------------------------
183 template <typename BufferT, typename IterT>
184 auto createKeyCapMap (IterT begin, IterT end) -> HashMap<BufferT>
185 {
186  HashMap<BufferT> fkey_cap_map;
187  fkey_cap_map.reserve(std::size_t(std::distance(begin, end)));
188 
189  std::for_each ( begin
190  , end
191  , [&fkey_cap_map] (const auto& item)
192  {
193  if ( item.string && item.length != 0 )
194  fkey_cap_map[{item.string, item.length}] = item.num;
195  } );
196 
197  return fkey_cap_map;
198 }
199 
200 //----------------------------------------------------------------------
201 template <typename BufferT>
202 auto createKeyMap() -> HashMap<BufferT>
203 {
204  auto& fkey_table = FKeyMap::getKeyMap();
205  HashMap<BufferT> fkey_map;
206 
207  // Reserve more space (1.25×) to avoid rehashing during construction
208  fkey_map.reserve((fkey_table.size() * 5) / 4); // ⁵⁄₄ = 1.25
209 
210  for (auto& item : fkey_table)
211  if ( item.length != 0 ) // Note: item.string is an array and always allocated
212  fkey_map[{item.string.data(), item.length}] = item.num;
213 
214  return fkey_map;
215 }
216 
217 } // namespace internal
218 
219 //----------------------------------------------------------------------
220 template <typename BufferT>
221 auto getKeyCapMap() -> internal::HashMap<BufferT>&
222 {
223  using HashMapType = internal::HashMap<BufferT>;
224  static const auto& fkey_cap_map = std::make_unique<HashMapType>(internal::createKeyCapMap<BufferT>());
225  return *fkey_cap_map;
226 }
227 
228 //----------------------------------------------------------------------
229 template <typename BufferT, typename IterT>
230 void setKeyCapMap (IterT begin, IterT end)
231 {
232  getKeyCapMap<BufferT>() = internal::createKeyCapMap<BufferT>(begin, end);
233 }
234 
235 //----------------------------------------------------------------------
236 template <typename BufferT>
237 auto getKeyMap() -> internal::HashMap<BufferT>&
238 {
239  using HashMapType = internal::HashMap<BufferT>;
240  static const auto& fkey_map = std::make_unique<HashMapType>(internal::createKeyMap<BufferT>());
241  return *fkey_map;
242 }
243 
244 //----------------------------------------------------------------------
245 template <typename BufferT>
246 auto getTermcapKey (const BufferT& char_rbuf) -> FKey
247 {
248  auto& hashmap = getKeyCapMap<BufferT>();
249  auto iter = hashmap.find(internal::KeySequence<BufferT>(char_rbuf));
250 
251  if ( iter != hashmap.end() ) // found
252  return iter->second;
253 
254  return FKey::None;
255 }
256 
257 //----------------------------------------------------------------------
258 template <typename BufferT>
259 auto getKnownKey (const BufferT& char_rbuf) -> FKey
260 {
261  auto& hashmap = getKeyMap<BufferT>();
262  auto iter = hashmap.find(internal::KeySequence<BufferT>(char_rbuf));
263 
264  if ( iter != hashmap.end() ) // found
265  return iter->second;
266 
267  return FKey::None;
268 }
269 
270 } // namespace fkeyhashmap
271 
272 } // namespace finalcut
273 
274 #endif // FKEYHASHMAP_H
Definition: class_template.cpp:25
Definition: fkey_hashmap.h:47