Lamp-Da 0.1
A compact lantern project
Loading...
Searching...
No Matches
keystore.hpp
Go to the documentation of this file.
1
5#ifndef MODES_HARDWARD_KEYSTORE_HPP
6#define MODES_HARDWARD_KEYSTORE_HPP
7
10
12
14
15#include <cstring>
16#include <array>
17
20
34static constexpr uint32_t storeUid = utils::hash("StoreRev:v01");
35
37static constexpr uint32_t map32to31hash(uint32_t a)
38{
39 uint32_t lsb = a & 0b1; // mix the lost LSB info into the 13th bit
40 uint32_t val = (a ^ storeUid ^ (lsb << 14));
41 return val >> 1;
42}
43
45template<int16_t N> static constexpr uint32_t LMBD_INLINE hash(const char (&s)[N])
46{
47 static_assert(N - 1 <= 14, "Please use keys shorter than 14 bytes!");
48 return map32to31hash(utils::hash(s, N));
49}
50
56template<int16_t N> static inline void LMBD_INLINE setValue(const char (&key)[N], uint32_t value)
57{
58 static_assert(N - 1 <= 14, "Please use keys shorter than 14 bytes!");
59 bsp::filesystem::user::set_value(hash(key), value);
60}
61
68template<int16_t N> static inline bool LMBD_INLINE getValue(const char (&key)[N], uint32_t& out)
69{
70 static_assert(N - 1 <= 14, "Please use keys shorter than 14 bytes!");
71 return bsp::filesystem::user::get_value(hash(key), out);
72}
73
76
80static inline void LMBD_INLINE migrateIfNeeded()
81{
82 if (not bsp::filesystem::user::doKeyExists(storeUid))
83 {
84 bsp::filesystem::user::set_value(storeUid, storeUid);
85 }
86
87 uint32_t out = storeUid ^ 0xff;
88 if (not bsp::filesystem::user::get_value(storeUid, out))
89 {
90 bsp::filesystem::user::set_value(storeUid, storeUid);
92 }
93
94 if (out != storeUid)
95 {
97
98 bsp::filesystem::user::set_value(storeUid, storeUid);
101 }
102}
103
112static constexpr uint32_t indexKeyFlag = (1 << 31);
113
130enum class PrefixValues : uint32_t
131{
132 generalKeys = indexKeyFlag | (0x0 << 29),
133 managerKeys = indexKeyFlag | (0x1 << 29),
134 privateKeys = indexKeyFlag | (0x2 << 29),
135 invalidKeys = indexKeyFlag | (0x3 << 29),
136};
137
139static constexpr uint32_t noGroupIndex = 15;
140
142static constexpr uint32_t noModeIndex = 31;
143
145static constexpr uint32_t LMBD_INLINE
146indexKeyFor(PrefixValues prefix, uint32_t groupId, uint32_t modeId, uint32_t offset, uint32_t index)
147{
148 uint32_t rawPrefix = (uint32_t)prefix;
149
150 assert((rawPrefix >> 31) == 0b1); // prefix on 2 of the MSBs +indexKeyFlag
151 assert((groupId >> 4) == 0); // groupId on 4 bits (0-14)
152 assert((modeId >> 5) == 0); // modeId on 5 bits (0-30)
153 assert((offset >> 4) == 0); // offset on 4 bits (0-15)
154 assert((index >> 16) == 0); // index on 16 bits (0-65535)
155
156 return rawPrefix | (groupId << 25) | (modeId << 20) | (offset << 16) | index;
157}
158
160template<typename _EnumTy, int _groupId, int _modeId, PrefixValues _prefix = PrefixValues::generalKeys> struct KeyStore
161{
162 using EnumTy = _EnumTy;
163 static constexpr uint32_t groupId = _groupId < 0 ? noGroupIndex : _groupId;
164 static constexpr uint32_t modeId = _modeId < 0 ? noModeIndex : _modeId;
165 static constexpr PrefixValues prefix = _prefix;
166
167 // it's magic!
168 static constexpr uint16_t storeIdKey = 0xafff;
169
170 static_assert(sizeof(EnumTy) == sizeof(uint16_t), "uint16_t enum only");
171 static_assert((groupId >> 4) == 0, "Group index must fit on 4 bits!");
172 static_assert((modeId >> 5) == 0, "Mode index must fit on 5 bits!");
173
174 // \private maps to ContextTy::KeyProxy::setValue()
175 template<EnumTy key, typename T> static inline void LMBD_INLINE setValue(T value)
176 {
177 using valueTy = std::remove_cv_t<std::remove_reference_t<T>>;
178 constexpr uint16_t rawKey = (uint16_t)key;
179
180 static_assert(storeIdKey != rawKey, "error: key can not match storeIdKey (0xafff)");
181
182 // simple case: value is uint32_t, store it as-is
183 if constexpr (std::is_same_v<valueTy, uint32_t>)
184 {
185 constexpr auto idx = indexKeyFor(prefix, groupId, modeId, 0, rawKey);
187
188 // small case: value is smaller than uint32_t, store it on a uint32_t
189 }
190 else if constexpr (sizeof(valueTy) <= sizeof(uint32_t))
191 {
192 uint32_t storage = 0;
193 details::bit_cast<sizeof(value)>(storage, value);
194 setValue<key>(storage);
195
196 // large case: value is stored on up to 16 uint32_t
197 }
198 else if constexpr (sizeof(valueTy) <= 16 * sizeof(uint32_t))
199 {
200 constexpr uint8_t N = ((sizeof(valueTy) - 1) / sizeof(uint32_t)) + 1;
201 std::array<uint32_t, N> storage {};
202 details::bit_cast<sizeof(value)>(storage, value);
203 for (uint8_t I = 0; I < N; ++I)
204 {
205 uint32_t off = indexKeyFor(prefix, groupId, modeId, I, rawKey);
206 bsp::filesystem::user::set_value(off, storage[I]);
207 }
208 }
209 else
210 {
211 static_assert(sizeof(valueTy) <= 64, "KeyStore values limited to 64 bytes!");
212 }
213 }
214
215 // \private maps to ContextTy::KeyProxy::getValue()
216 template<EnumTy key, typename T> static inline bool LMBD_INLINE getValue(T& output)
217 {
218 constexpr uint16_t rawKey = (uint16_t)key;
219
220 static_assert(storeIdKey != rawKey, "error: key can not match storeIdKey (0xafff)");
221
222 // simple case: value is uint32_t, get it as-is
223 if constexpr (std::is_same_v<T, uint32_t>)
224 {
225 constexpr auto idx = indexKeyFor(prefix, groupId, modeId, 0, rawKey);
226 return bsp::filesystem::user::get_value(idx, output);
227
228 // small case: value is smaller than uint32_t, get it on a uint32_t
229 }
230 else if constexpr (sizeof(T) <= sizeof(uint32_t))
231 {
232 uint32_t storage = 0;
233 if (not getValue<key, uint32_t>(storage))
234 {
235 return false;
236 }
237
238 details::bit_cast<sizeof(output)>(output, storage);
239 return true;
240
241 // large case: value is stored on up to 16 uint32_t
242 }
243 else if constexpr (sizeof(T) <= 16 * sizeof(uint32_t))
244 {
245 constexpr uint8_t N = ((sizeof(T) - 1) / sizeof(uint32_t)) + 1;
246 std::array<uint32_t, N> storage {};
247 for (uint8_t I = 0; I < N; ++I)
248 {
249 uint32_t off = indexKeyFor(prefix, groupId, modeId, I, rawKey);
250 if (not bsp::filesystem::user::get_value(off, storage[I]))
251 {
252 return false;
253 }
254 }
255
256 details::bit_cast<sizeof(output)>(output, storage);
257 return true;
258 }
259 else
260 {
261 static_assert(sizeof(T) <= 64, "KeyStore values limited to 64 bytes!");
262 }
263 return false;
264 }
265
266 // \private maps to ContextTy::KeyProxy::getValue(defaultValue)
267 template<EnumTy key, typename T> static inline void LMBD_INLINE getValue(T& output, T defValue)
268 {
269 if (not getValue<key, T>(output))
270 {
271 output = defValue;
272 }
273 }
274
275 // \private maps to ContextTy::KeyProxy::hasValue
276 template<EnumTy key, typename T = uint32_t> static inline bool LMBD_INLINE hasValue()
277 {
278 T output;
279 return getValue<key, T>(output);
280 }
281
282 // \private empty store if \p storeId mismatch with value at \p storeIdKey
283 template<uint32_t storeId> static void migrateStoreIfNeeded()
284 {
285 constexpr auto idx = indexKeyFor(prefix, groupId, modeId, 0, storeIdKey);
286
287 // retrieve storeId from storage
288 uint32_t otherId = 0;
289 if (not bsp::filesystem::user::get_value(idx, otherId))
290 {
291 otherId = storeId;
293 }
294
295 // if it don't match our storeId, clean storage from our old keys
296 if (otherId != storeId || otherId == 0)
297 {
298 constexpr uint32_t select = 0xfff00000; // all but offset
299 constexpr uint32_t masked = idx & select;
302 }
303 }
304};
305
307template<uint32_t baseId, typename AllModes> static constexpr uint32_t derivateStoreIdImpl()
308{
309 constexpr uint32_t MixCstA = 0x8af8901d, MixCstB = 0x2f9c7c90;
310 constexpr uint8_t NbModes = std::tuple_size_v<AllModes>;
311
312 uint32_t storeId = baseId;
313 details::unroll<NbModes>([&](auto Idx) {
314 constexpr uint8_t I = decltype(Idx)::value;
315 using ModeHere = std::tuple_element_t<I, AllModes>;
316 using StoreHere = StoreEnumOf<ModeHere>;
317 constexpr bool hasStore = not std::is_same_v<StoreHere, NoStoreHere>;
318
319 uint32_t storeIdHere = 0;
320 if constexpr (hasStore)
321 {
322 storeIdHere = ModeHere::storeId;
323 }
324
325 // straightforward mix function
326 storeId += MixCstA;
327 storeId = (storeId << 7) ^ (storeId >> (32 - 7));
328 storeId ^= MixCstB;
329
330 storeId += storeIdHere;
331 });
332
333 return storeId;
334}
335
337template<uint32_t baseId, typename AllModes> static constexpr uint32_t derivateStoreId =
338 derivateStoreIdImpl<baseId, AllModes>();
339
340} // namespace lampda::modes::store
341
342#endif
High level actions on the file system.
Contains shorthand macro definitions.
bool format()
Delete the user file.
Definition: filesystem.cpp:338
bool doKeyExists(const uint32_t key)
Return true if the given key exists in the filesystem.
Definition: filesystem.cpp:270
uint32_t dropMatchingKeys(const uint32_t bitMatch, const uint32_t bitSelect)
Drop all keys using the given bit prefix.
Definition: filesystem.cpp:291
void write_to_file()
Write the user parameters to a file.
Definition: filesystem.cpp:323
bool get_value(const uint32_t key, uint32_t &value)
Check and return a value stored in a filesystem.
Definition: filesystem.cpp:272
bool load_from_file()
Load user values from memory.
Definition: filesystem.cpp:336
void set_value(const uint32_t key, const uint32_t value)
Store a key/value in the filesystem.
Definition: filesystem.cpp:289
void clear_cached()
clear the stored values in the currently loaded file system.
Definition: filesystem.cpp:317
Mode key store interface, see ContextTy::KeyProxy.
Definition: keystore.hpp:19
static void LMBD_INLINE setValue(const char(&key)[N], uint32_t value)
Set value for named key and read in in out.
Definition: keystore.hpp:56
static bool LMBD_INLINE getValue(const char(&key)[N], uint32_t &out)
Get value for named key and write it in out.
Definition: keystore.hpp:68
static void LMBD_INLINE migrateIfNeeded()
Check for migration and erase all values if needed.
Definition: keystore.hpp:80
static void clear_stored()
Force clear the stored parameters.
Definition: keystore.hpp:75
static constexpr uint32_t hash(const T s, const uint16_t maxSize=14, const uint16_t off=0)
Hash input string into a 32-bit unsigned integer.
Definition: utils.h:179
Define templated tools to analyze the manager objects.
Define useful functions.