diff --git a/samples/matter/common/src/bridge/bridge_manager.h b/samples/matter/common/src/bridge/bridge_manager.h index 0fcbdb509d92..c2b78e5a9f8f 100644 --- a/samples/matter/common/src/bridge/bridge_manager.h +++ b/samples/matter/common/src/bridge/bridge_manager.h @@ -8,6 +8,7 @@ #include "binding/binding_handler.h" #include "bridge_util.h" +#include "util/finite_map.h" #include "bridged_device_data_provider.h" #include "matter_bridged_device.h" @@ -177,7 +178,7 @@ class BridgeManager { static constexpr uint8_t kMaxDataProviders = CONFIG_BRIDGE_MAX_BRIDGED_DEVICES_NUMBER; - using DeviceMap = FiniteMap; + using DeviceMap = FiniteMap; /** * @brief Add pair of single bridged device and its data provider using optional index and endpoint id. diff --git a/samples/matter/common/src/bridge/util/bridge_util.h b/samples/matter/common/src/bridge/util/bridge_util.h index 3c5644ec79f3..977e405ee9ba 100644 --- a/samples/matter/common/src/bridge/util/bridge_util.h +++ b/samples/matter/common/src/bridge/util/bridge_util.h @@ -12,7 +12,8 @@ #include #include -namespace Nrf { +namespace Nrf +{ /* DeviceFactory template container allows to instantiate a map which @@ -55,96 +56,4 @@ template class DeviceFactory CreationMap mCreationMap; }; -/* - FiniteMap template container allows to wrap mappings between uint16_t-type key and T-type value. - The size or the container is predefined at compilation time, therefore - the maximum number of stored elements must be well known. FiniteMap owns - inserted values, meaning that once the user inserts a value it will not longer - be valid outside of the container, i.e. FiniteMap cannot return stored object by copy. - FiniteMap's API offers basic operations like: - * inserting new values under provided key (Insert) - * erasing existing item under given key (Erase) - this operation takes care about the duplicated items, - meaning that pointer under given key is released only if the same address is not present elsewhere in the map - * retrieving values stored under provided key ([] operator) - * checking if the map contains a non-null value under given key (Contains) - * retrieving a number of free slots available in the map (FreeSlots) - * iterating though stored item via publicly available mMap member - Prerequisites: - * T must have move semantics and bool()/==operators implemented -*/ -template struct FiniteMap { - static constexpr uint16_t kInvalidKey{ N + 1 }; - struct Item { - /* Initialize with invalid key (0 is a valid key) */ - uint16_t key{ kInvalidKey }; - T value; - }; - - bool Insert(uint16_t key, T &&value) - { - if (Contains(key)) { - /* The key with sane value already exists in the map, return prematurely. */ - return false; - } else if (mElementsCount < N) { - mMap[key].key = key; - mMap[key].value = std::move(value); - mElementsCount++; - } - return true; - } - - bool Erase(uint16_t key) - { - const auto &it = std::find_if(std::begin(mMap), std::end(mMap), - [key](const Item &item) { return item.key == key; }); - if (it != std::end(mMap) && it->value) { - it->value = T{}; - it->key = kInvalidKey; - mElementsCount--; - return true; - } - return false; - } - - /* Always use Constains() before using operator[]. */ - T &operator[](uint16_t key) - { - static T dummyObject; - for (auto &it : mMap) { - if (key == it.key) - return it.value; - } - return dummyObject; - } - - bool Contains(uint16_t key) - { - for (auto &it : mMap) { - if (key == it.key) - return true; - } - return false; - } - std::size_t FreeSlots() { return N - mElementsCount; } - - uint8_t GetDuplicatesCount(const T &value, uint16_t *key) - { - /* Find the first duplicated item and return its key, - so that the application can handle the duplicate by itself. */ - *key = kInvalidKey; - uint8_t numberOfDuplicates = 0; - for (auto it = std::begin(mMap); it != std::end(mMap); ++it) { - if (it->value == value) { - *(key++) = it->key; - numberOfDuplicates++; - } - } - - return numberOfDuplicates; - } - - Item mMap[N]; - uint16_t mElementsCount{ 0 }; -}; - } /* namespace Nrf */ diff --git a/samples/matter/common/src/util/finite_map.h b/samples/matter/common/src/util/finite_map.h new file mode 100644 index 000000000000..63458e2bfb06 --- /dev/null +++ b/samples/matter/common/src/util/finite_map.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Nrf +{ +/* + FiniteMap template container allows to wrap mappings between T1-type trivial key and T2-type value. + The size or the container is predefined at compilation time, therefore + the maximum number of stored elements must be well known. FiniteMap owns + inserted values, meaning that once the user inserts a value it will not longer + be valid outside of the container, i.e. FiniteMap cannot return stored object by copy. + FiniteMap's API offers basic operations like: + * inserting new values under provided key (Insert) + * erasing existing items under a given key (Erase) - this operation does not take care of the + duplicated items, meaning that the pointer under a given key is released unconditionally + and the responsibility for the duplications is on the application side. + * retrieving values stored under provided key ([] operator) + * checking if the map contains a non-null value under given key (Contains) + * retrieving a number of free slots available in the map (FreeSlots) + * iterating though stored item via publicly available mMap member + * retrieving the first free slot (GetFirstFreeSlot) + Prerequisites: + * T1 must be trivial and the maximum numeric limit for the T1-type value is reserved and assigned as an invalid key. + * T2 must have move semantics and bool()/==operators implemented +*/ +template struct FiniteMap { + static_assert(std::is_trivial_v); + + static constexpr T1 kInvalidKey{ std::numeric_limits::max() }; + static constexpr std::size_t kNoSlotsFound{ N + 1 }; + + struct Item { + /* Initialize with invalid key (0 is a valid key) */ + T1 key{ kInvalidKey }; + T2 value; + }; + + bool Insert(T1 key, T2 &&value) + { + if (Contains(key)) { + /* The key with sane value already exists in the map, return prematurely. */ + return false; + } else if (mElementsCount < N) { + std::size_t slot = GetFirstFreeSlot(); + if (slot == kNoSlotsFound) { + return false; + } + mMap[slot].key = key; + mMap[slot].value = std::move(value); + mElementsCount++; + } + return true; + } + + bool Erase(T1 key) + { + const auto &it = std::find_if(std::begin(mMap), std::end(mMap), + [key](const Item &item) { return item.key == key; }); + if (it != std::end(mMap)) { + it->value = T2{}; + it->key = kInvalidKey; + mElementsCount--; + return true; + } + return false; + } + + /* Always use Contains() before using operator[]. */ + T2 &operator[](T1 key) + { + static T2 dummyObject; + for (auto &it : mMap) { + if (key == it.key) + return it.value; + } + return dummyObject; + } + + bool Contains(T1 key) + { + for (auto &it : mMap) { + if (key == it.key) + return true; + } + return false; + } + + std::size_t FreeSlots() { return N - mElementsCount; } + + std::size_t GetFirstFreeSlot() + { + std::size_t foundIndex = 0; + for (auto &it : mMap) { + if (kInvalidKey == it.key) + return foundIndex; + foundIndex++; + } + return kNoSlotsFound; + } + + uint8_t GetDuplicatesCount(const T2 &value, T1 *key) + { + /* Find the first duplicated item and return its key, + so that the application can handle the duplicate by itself. */ + *key = kInvalidKey; + uint8_t numberOfDuplicates = 0; + for (auto it = std::begin(mMap); it != std::end(mMap); ++it) { + if (it->value == value) { + *(key++) = it->key; + numberOfDuplicates++; + } + } + + return numberOfDuplicates; + } + + Item mMap[N]; + uint16_t mElementsCount{ 0 }; +}; + +} /* namespace Nrf */