29size_t GetKeyData(
size_t offset)
32 ReadFlashOrExit(offset, key);
42size_t GetKeyName(
size_t offset) {
return offset + AlignSize(
sizeof(
KeyInfo)); }
50size_t GetKeySpan(
const KeyInfo& key)
61size_t GetKeySize(
size_t offset)
64 ReadFlashOrExit(offset, key);
65 return GetKeySpan(key);
73size_t GetNextKey(
size_t offset) {
return offset + GetKeySize(offset); }
81static bool IsKeyLive(
const KeyInfo& key)
99 ReadFlashOrExit(flag_offset, value);
105 WriteFlashOrExit(flag_offset, value);
118void LinkKey(BlockType block,
size_t last_key_offset)
120 if (last_key_offset == GetSentinelOffset(block))
135void WriteKeyHeader(
size_t key_offset,
size_t name_len,
size_t size)
157bool NextChainKey(BlockType block,
size_t& key_offset,
KeyInfo& key)
164 const size_t limit = GetBlockOffset(block) + GetChecksumOffset();
165 const size_t next_offset = key_offset + GetKeySpan(key);
166 if (next_offset + AlignSize(
sizeof(
KeyInfo)) > limit)
172 ReadFlashOrExit(next_offset, next_key);
173 if (next_offset + GetKeySpan(next_key) > limit)
178 key_offset = next_offset;
189size_t GetLastKey(BlockType block)
191 size_t key_offset = GetSentinelOffset(block);
193 ReadFlashOrExit(key_offset, key);
194 while (NextChainKey(block, key_offset, key))
209bool KeyDataCompare(
size_t offset,
const void* data,
size_t size)
212 ReadFlashOrExit(offset, key);
213 size_t key_data_offset = GetKeyData(offset);
214 uint8_t data_buffer = 0;
215 for (
size_t i = 0; i < size; i++)
217 ReadFlashOrExit(key_data_offset + i, data_buffer);
218 if (data_buffer != (
reinterpret_cast<const uint8_t*
>(data))[i])
234bool KeyNameCompare(
size_t offset,
const char* name)
237 ReadFlashOrExit(offset, key);
240 uint8_t data_buffer = 0;
241 ReadFlashOrExit(offset + AlignSize(
sizeof(
KeyInfo)) + i, data_buffer);
242 if (data_buffer != name[i])
262bool IsKeyNameTerminated(
size_t key_offset,
const KeyInfo& key)
269 uint8_t last_byte = 0xFF;
270 ReadFlashOrExit(GetKeyName(key_offset) + name_len - 1, last_byte);
271 return last_byte == 0;
283size_t FindKey(
const char* name,
size_t& dead_keys)
285 size_t key_offset = GetSentinelOffset(BlockType::MAIN);
287 ReadFlashOrExit(key_offset, key);
290 while (NextChainKey(BlockType::MAIN, key_offset, key))
297 if (!KeyNameCompare(key_offset, name))
318size_t SearchKey(
const char* name)
320 size_t dead_keys = 0;
321 const size_t ans = FindKey(name, dead_keys);
322 if (dead_keys > recycle_threshold_)
325 return FindKey(name, dead_keys);
342ErrorCode ReserveKey(
size_t name_len,
size_t size,
size_t& last_key_offset)
344 const size_t needed =
345 AlignSize(
sizeof(
KeyInfo)) + AlignSize(name_len) + AlignSize(size);
346 if (AvailableSize() < needed)
349 if (AvailableSize() < needed)
351 return ErrorCode::FULL;
354 last_key_offset = GetLastKey(BlockType::MAIN);
355 return ErrorCode::OK;
365ErrorCode AddKey(
const char* name,
const void* data,
size_t size)
369 return SetKey(name, data, size);
372 const size_t name_len = strlen(name) + 1;
373 size_t last_key_offset = 0;
374 const ErrorCode ec = ReserveKey(name_len, size, last_key_offset);
375 if (ec != ErrorCode::OK)
380 const size_t key_offset = GetNextKey(last_key_offset);
381 WriteKeyHeader(key_offset, name_len, size);
382 WriteFlashOrExit(GetKeyName(key_offset),
383 {
reinterpret_cast<const uint8_t*
>(name), name_len});
384 WriteFlashOrExit(GetKeyData(key_offset),
385 {
reinterpret_cast<const uint8_t*
>(data), size});
387 LinkKey(BlockType::MAIN, last_key_offset);
388 return ErrorCode::OK;
410ErrorCode SetKey(
const char* name,
const void* data,
size_t size,
bool recycle =
true)
412 const size_t key_offset = SearchKey(name);
415 return ErrorCode::FAILED;
419 ReadFlashOrExit(key_offset, key);
422 return ErrorCode::FAILED;
424 if (!KeyDataCompare(key_offset, data, size))
426 return ErrorCode::OK;
430 if (AvailableSize() <
431 AlignSize(
sizeof(
KeyInfo)) + AlignSize(name_len) + AlignSize(size))
435 return ErrorCode::FULL;
438 return SetKey(name, data, size,
false);
441 const size_t last_key_offset = GetLastKey(BlockType::MAIN);
442 const size_t new_key_offset = GetNextKey(last_key_offset);
443 WriteKeyHeader(new_key_offset, name_len, size);
444 CopyFlashData(GetKeyName(new_key_offset), GetKeyName(key_offset), name_len);
445 WriteFlashOrExit(GetKeyData(new_key_offset),
446 {
reinterpret_cast<const uint8_t*
>(data), size});
449 LinkKey(BlockType::MAIN, last_key_offset);
450 return ErrorCode::OK;
469bool CompleteUnlinkedKey(
size_t last_key_offset,
size_t key_offset)
471 const size_t checksum_offset = GetChecksumOffset();
472 if (key_offset + AlignSize(
sizeof(
KeyInfo)) > checksum_offset)
478 ReadFlashOrExit(key_offset, key);
479 const size_t end_offset = key_offset + GetKeySpan(key);
481 end_offset > checksum_offset || !IsKeyNameTerminated(key_offset, key) ||
482 !IsErased(end_offset, checksum_offset))
487 char name[0x80] = {};
488 ReadFlashOrExit(GetKeyName(key_offset), RawData(name, key.
GetNameLength()));
489 size_t dead_keys = 0;
490 const size_t old_offset = FindKey(name, dead_keys);
494 ReadFlashOrExit(old_offset, old_key);
502 LinkKey(BlockType::MAIN, last_key_offset);
519void RepairMainChain()
521 size_t key_offset = GetSentinelOffset(BlockType::MAIN);
523 ReadFlashOrExit(key_offset, key);
524 size_t dead_keys = 0;
525 while (NextChainKey(BlockType::MAIN, key_offset, key))
534 const size_t tail_offset = key_offset + GetKeySpan(key);
535 if (chain_complete && IsErased(tail_offset, GetChecksumOffset()))
537 if (dead_keys > recycle_threshold_)
544 if (chain_complete && CompleteUnlinkedKey(key_offset, tail_offset))
读写对齐布尔位图块的工具 Helpers for reading and writing aligned boolean flag blocks.
static void SetFlag(BlockBoolData< BlockSize > &obj, bool value)
把一个布尔值编码进位图块 / Encode one boolean value into a flag block.
static bool ReadFlag(const BlockBoolData< BlockSize > &obj)
从位图块读取布尔值 / Decode one boolean value from a flag block.
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
size_t OffsetOf(MemberType OwnerType::*member) noexcept
计算成员在宿主对象中的偏移量 Computes the offset of a member within the owning object
按最小写入单元存放布尔位图块 Boolean flag block stored in one aligned write unit span.
键信息结构,存储键的元数据 Structure containing key metadata.
BlockBoolData< MinWriteSize > uninit
该键是否未初始化
BlockBoolData< MinWriteSize > available_flag
该键是否有效
uint32_t GetDataSize() const
获取数据字节数 / Get the payload size in bytes.
void SetNameLength(uint8_t len)
设置键名长度 / Set the key name length.
BlockBoolData< MinWriteSize > no_next_key
是否是最后一个键
void SetDataSize(uint32_t size)
设置数据字节数 / Set the payload size in bytes.
uint8_t GetNameLength() const
获取键名长度 / Get the key name length.