1 /*
2 * Copyright (c) 2020 - 2023, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35 /**@file nrf_802154_kvmap.c
36 * @brief Simple key-value map.
37 */
38
39 #include "nrf_802154_kvmap.h"
40
41 #include "nrf_802154_serialization_crit_sect.h"
42
43 #include <stdint.h>
44 #include <string.h>
45
46 #define NRF_802154_KVMAP_ITEMSIZE(key_size, val_size) ((key_size) + (val_size))
47
item_ptr_by_idx_get(const nrf_802154_kvmap_t * p_kvmap,size_t idx)48 static inline uint8_t * item_ptr_by_idx_get(const nrf_802154_kvmap_t * p_kvmap, size_t idx)
49 {
50 return ((uint8_t *)(p_kvmap->p_memory)) +
51 (idx * NRF_802154_KVMAP_ITEMSIZE(p_kvmap->key_size, p_kvmap->val_size));
52 }
53
item_value_write(const nrf_802154_kvmap_t * p_kvmap,uint8_t * p_item,const void * p_value)54 static void item_value_write(const nrf_802154_kvmap_t * p_kvmap,
55 uint8_t * p_item,
56 const void * p_value)
57 {
58 if (p_kvmap->val_size != 0U)
59 {
60 memcpy(p_item + p_kvmap->key_size, p_value, p_kvmap->val_size);
61 }
62 }
63
item_idx_by_key_search(const nrf_802154_kvmap_t * p_kvmap,const void * p_key)64 static size_t item_idx_by_key_search(const nrf_802154_kvmap_t * p_kvmap, const void * p_key)
65 {
66 size_t item_size = NRF_802154_KVMAP_ITEMSIZE(p_kvmap->key_size, p_kvmap->val_size);
67 uint8_t * p_item = p_kvmap->p_memory;
68 size_t idx;
69
70 /* Linear search */
71 for (idx = 0U; idx < p_kvmap->count; ++idx, p_item += item_size)
72 {
73 if (memcmp(p_item, p_key, p_kvmap->key_size) == 0)
74 {
75 /* Hit! */
76 break;
77 }
78 }
79
80 return idx;
81 }
82
nrf_802154_kvmap_init(nrf_802154_kvmap_t * p_kvmap,void * p_memory,size_t memsize,size_t key_size,size_t val_size)83 void nrf_802154_kvmap_init(nrf_802154_kvmap_t * p_kvmap,
84 void * p_memory,
85 size_t memsize,
86 size_t key_size,
87 size_t val_size)
88 {
89 p_kvmap->p_memory = p_memory;
90 p_kvmap->capacity = memsize / NRF_802154_KVMAP_ITEMSIZE(key_size, val_size);
91 p_kvmap->key_size = key_size;
92 p_kvmap->val_size = val_size;
93 p_kvmap->count = 0U;
94 }
95
nrf_802154_kvmap_add(nrf_802154_kvmap_t * p_kvmap,const void * p_key,const void * p_value)96 bool nrf_802154_kvmap_add(nrf_802154_kvmap_t * p_kvmap, const void * p_key, const void * p_value)
97 {
98 uint32_t crit_sect = 0UL;
99 size_t idx;
100 bool success = true;
101
102 nrf_802154_serialization_crit_sect_enter(&crit_sect);
103
104 idx = item_idx_by_key_search(p_kvmap, p_key);
105 if (idx < p_kvmap->count)
106 {
107 /* Item already present */
108 uint8_t * p_item = item_ptr_by_idx_get(p_kvmap, idx);
109
110 item_value_write(p_kvmap, p_item, p_value);
111 }
112 else if (p_kvmap->count >= p_kvmap->capacity)
113 {
114 /* Item not found, but the map is at full capacity. Don't add the item */
115 success = false;
116 }
117 else
118 {
119 /* Not found, try to add next at p_kvmap->count */
120 uint8_t * p_item = item_ptr_by_idx_get(p_kvmap, p_kvmap->count);
121
122 memcpy(p_item, p_key, p_kvmap->key_size);
123 item_value_write(p_kvmap, p_item, p_value);
124
125 p_kvmap->count++;
126 }
127
128 nrf_802154_serialization_crit_sect_exit(crit_sect);
129
130 return success;
131 }
132
nrf_802154_kvmap_remove(nrf_802154_kvmap_t * p_kvmap,const void * p_key)133 bool nrf_802154_kvmap_remove(nrf_802154_kvmap_t * p_kvmap, const void * p_key)
134 {
135 uint32_t crit_sect = 0UL;
136 size_t idx;
137 bool success = true;
138
139 nrf_802154_serialization_crit_sect_enter(&crit_sect);
140
141 idx = item_idx_by_key_search(p_kvmap, p_key);
142 if (idx >= p_kvmap->count)
143 {
144 /* Key not found */
145 success = false;
146 }
147 else
148 {
149 p_kvmap->count--;
150 if (idx < p_kvmap->count)
151 {
152 const uint8_t * p_last_item = item_ptr_by_idx_get(p_kvmap, p_kvmap->count);
153 uint8_t * p_item = item_ptr_by_idx_get(p_kvmap, idx);
154
155 memcpy(p_item,
156 p_last_item,
157 NRF_802154_KVMAP_ITEMSIZE(p_kvmap->key_size, p_kvmap->val_size));
158 }
159 else
160 {
161 /* We hit last item, no item move necessary */
162 }
163 }
164
165 nrf_802154_serialization_crit_sect_exit(crit_sect);
166
167 return success;
168 }
169
nrf_802154_kvmap_search(const nrf_802154_kvmap_t * p_kvmap,const void * p_key,void * p_value)170 bool nrf_802154_kvmap_search(const nrf_802154_kvmap_t * p_kvmap,
171 const void * p_key,
172 void * p_value)
173 {
174 uint32_t crit_sect = 0UL;
175 size_t idx;
176 bool success = true;
177
178 nrf_802154_serialization_crit_sect_enter(&crit_sect);
179
180 idx = item_idx_by_key_search(p_kvmap, p_key);
181 if (idx >= p_kvmap->count)
182 {
183 /* Key not found */
184 success = false;
185 }
186 else
187 {
188 const uint8_t * p_item = item_ptr_by_idx_get(p_kvmap, idx);
189
190 /* Copy value associated with the key if requested and values are present */
191 if ((p_value != NULL) && (p_kvmap->val_size != 0U))
192 {
193 memcpy(p_value, p_item + p_kvmap->key_size, p_kvmap->val_size);
194 }
195 }
196
197 nrf_802154_serialization_crit_sect_exit(crit_sect);
198
199 return success;
200 }
201