1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "nvs_item_hash_list.hpp"
16
17 namespace nvs
18 {
19
HashList()20 HashList::HashList()
21 {
22 }
23
clear()24 void HashList::clear()
25 {
26 for (auto it = mBlockList.begin(); it != mBlockList.end();) {
27 auto tmp = it;
28 ++it;
29 mBlockList.erase(tmp);
30 delete static_cast<HashListBlock*>(tmp);
31 }
32 }
33
~HashList()34 HashList::~HashList()
35 {
36 clear();
37 }
38
HashListBlock()39 HashList::HashListBlock::HashListBlock()
40 {
41 static_assert(sizeof(HashListBlock) == HashListBlock::BYTE_SIZE,
42 "cache block size calculation incorrect");
43 }
44
insert(const Item & item,size_t index)45 esp_err_t HashList::insert(const Item& item, size_t index)
46 {
47 const uint32_t hash_24 = item.calculateCrc32WithoutValue() & 0xffffff;
48 // add entry to the end of last block if possible
49 if (mBlockList.size()) {
50 auto& block = mBlockList.back();
51 if (block.mCount < HashListBlock::ENTRY_COUNT) {
52 block.mNodes[block.mCount++] = HashListNode(hash_24, index);
53 return ESP_OK;
54 }
55 }
56 // if the above failed, create a new block and add entry to it
57 HashListBlock* newBlock = new (std::nothrow) HashListBlock;
58
59 if (!newBlock) return ESP_ERR_NO_MEM;
60
61 mBlockList.push_back(newBlock);
62 newBlock->mNodes[0] = HashListNode(hash_24, index);
63 newBlock->mCount++;
64
65 return ESP_OK;
66 }
67
erase(size_t index)68 bool HashList::erase(size_t index)
69 {
70 for (auto it = mBlockList.begin(); it != mBlockList.end();) {
71 bool haveEntries = false;
72 bool foundIndex = false;
73 for (size_t i = 0; i < it->mCount; ++i) {
74 if (it->mNodes[i].mIndex == index) {
75 it->mNodes[i].mIndex = 0xff;
76 foundIndex = true;
77 /* found the item and removed it */
78 }
79 if (it->mNodes[i].mIndex != 0xff) {
80 haveEntries = true;
81 }
82 if (haveEntries && foundIndex) {
83 /* item was found, and HashListBlock still has some items */
84 return true;
85 }
86 }
87 /* no items left in HashListBlock, can remove */
88 if (!haveEntries) {
89 auto tmp = it;
90 ++it;
91 mBlockList.erase(tmp);
92 delete static_cast<HashListBlock*>(tmp);
93 } else {
94 ++it;
95 }
96 if (foundIndex) {
97 /* item was found and empty HashListBlock was removed */
98 return true;
99 }
100 }
101
102 // item hasn't been present in cache");
103 return false;
104 }
105
find(size_t start,const Item & item)106 size_t HashList::find(size_t start, const Item& item)
107 {
108 const uint32_t hash_24 = item.calculateCrc32WithoutValue() & 0xffffff;
109 for (auto it = mBlockList.begin(); it != mBlockList.end(); ++it) {
110 for (size_t index = 0; index < it->mCount; ++index) {
111 HashListNode& e = it->mNodes[index];
112 if (e.mIndex >= start &&
113 e.mHash == hash_24 &&
114 e.mIndex != 0xff) {
115 return e.mIndex;
116 }
117 }
118 }
119 return SIZE_MAX;
120 }
121
122
123 } // namespace nvs
124