11739a20eSAndy Ritger /*
2eb5c7665SAndy Ritger * SPDX-FileCopyrightText: Copyright (c) 2015-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
31739a20eSAndy Ritger * SPDX-License-Identifier: MIT
41739a20eSAndy Ritger *
51739a20eSAndy Ritger * Permission is hereby granted, free of charge, to any person obtaining a
61739a20eSAndy Ritger * copy of this software and associated documentation files (the "Software"),
71739a20eSAndy Ritger * to deal in the Software without restriction, including without limitation
81739a20eSAndy Ritger * the rights to use, copy, modify, merge, publish, distribute, sublicense,
91739a20eSAndy Ritger * and/or sell copies of the Software, and to permit persons to whom the
101739a20eSAndy Ritger * Software is furnished to do so, subject to the following conditions:
111739a20eSAndy Ritger *
121739a20eSAndy Ritger * The above copyright notice and this permission notice shall be included in
131739a20eSAndy Ritger * all copies or substantial portions of the Software.
141739a20eSAndy Ritger *
151739a20eSAndy Ritger * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161739a20eSAndy Ritger * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171739a20eSAndy Ritger * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
181739a20eSAndy Ritger * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191739a20eSAndy Ritger * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201739a20eSAndy Ritger * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211739a20eSAndy Ritger * DEALINGS IN THE SOFTWARE.
221739a20eSAndy Ritger */
231739a20eSAndy Ritger #ifndef _NV_CONTAINERS_MAP_H_
241739a20eSAndy Ritger #define _NV_CONTAINERS_MAP_H_
251739a20eSAndy Ritger
261739a20eSAndy Ritger // Contains mix of C/C++ declarations.
271739a20eSAndy Ritger #include "containers/type_safety.h"
281739a20eSAndy Ritger
291739a20eSAndy Ritger #ifdef __cplusplus
301739a20eSAndy Ritger extern "C" {
311739a20eSAndy Ritger #endif
321739a20eSAndy Ritger
331739a20eSAndy Ritger #include "nvtypes.h"
341739a20eSAndy Ritger #include "nvmisc.h"
351739a20eSAndy Ritger #include "nvport/nvport.h"
361739a20eSAndy Ritger #include "utils/nvassert.h"
371739a20eSAndy Ritger
381739a20eSAndy Ritger /**
391739a20eSAndy Ritger * @defgroup NV_CONTAINERS_MAP Map
401739a20eSAndy Ritger *
411739a20eSAndy Ritger * @brief Map (ordered) from 64-bit integer keys to user-defined values.
421739a20eSAndy Ritger *
431739a20eSAndy Ritger * @details The provided interface is abstract, decoupling the user from the
441739a20eSAndy Ritger * underlying ordered map implementation. Two options are available with regard
451739a20eSAndy Ritger * to memory management, intrusive and non-intrusive. Users can select either
461739a20eSAndy Ritger * one based on different situations. Despite the two versions of the map,
471739a20eSAndy Ritger * the following implementation constraints are guaranteed.
481739a20eSAndy Ritger *
491739a20eSAndy Ritger * - Time Complexity:
501739a20eSAndy Ritger * * Operations are \b O(log N),
511739a20eSAndy Ritger * * Unless stated otherwise,
521739a20eSAndy Ritger * * Where N is the number of values in the map.
531739a20eSAndy Ritger *
541739a20eSAndy Ritger * - Memory Usage:
551739a20eSAndy Ritger * * \b O(N) memory is required for N values.
561739a20eSAndy Ritger * * Intrusive and non-intrusive variants are provided.
571739a20eSAndy Ritger * See @ref mem-ownership for further details.
581739a20eSAndy Ritger *
591739a20eSAndy Ritger * - Synchronization:
601739a20eSAndy Ritger * * \b None. The container is not thread-safe.
611739a20eSAndy Ritger * * Locking must be handled by the user if required.
621739a20eSAndy Ritger *
631739a20eSAndy Ritger */
641739a20eSAndy Ritger
651739a20eSAndy Ritger #define MAKE_MAP(mapTypeName, dataType) \
661739a20eSAndy Ritger typedef union mapTypeName##Iter \
671739a20eSAndy Ritger { \
681739a20eSAndy Ritger dataType *pValue; \
691739a20eSAndy Ritger MapIterBase iter; \
701739a20eSAndy Ritger } mapTypeName##Iter; \
711739a20eSAndy Ritger typedef union mapTypeName \
721739a20eSAndy Ritger { \
731739a20eSAndy Ritger NonIntrusiveMap real; \
741739a20eSAndy Ritger CONT_TAG_TYPE(MapBase, dataType, mapTypeName##Iter); \
751739a20eSAndy Ritger CONT_TAG_NON_INTRUSIVE(dataType); \
761739a20eSAndy Ritger } mapTypeName
771739a20eSAndy Ritger
781739a20eSAndy Ritger #define DECLARE_MAP(mapTypeName) \
791739a20eSAndy Ritger typedef union mapTypeName##Iter mapTypeName##Iter; \
801739a20eSAndy Ritger typedef union mapTypeName mapTypeName
811739a20eSAndy Ritger
821739a20eSAndy Ritger #define MAKE_INTRUSIVE_MAP(mapTypeName, dataType, node) \
831739a20eSAndy Ritger typedef union mapTypeName##Iter \
841739a20eSAndy Ritger { \
851739a20eSAndy Ritger dataType *pValue; \
861739a20eSAndy Ritger MapIterBase iter; \
871739a20eSAndy Ritger } mapTypeName##Iter; \
881739a20eSAndy Ritger typedef union mapTypeName \
891739a20eSAndy Ritger { \
901739a20eSAndy Ritger IntrusiveMap real; \
911739a20eSAndy Ritger CONT_TAG_TYPE(MapBase, dataType, mapTypeName##Iter); \
921739a20eSAndy Ritger CONT_TAG_INTRUSIVE(dataType, node); \
931739a20eSAndy Ritger } mapTypeName
941739a20eSAndy Ritger
951739a20eSAndy Ritger #define DECLARE_INTRUSIVE_MAP(mapTypeName) \
961739a20eSAndy Ritger typedef union mapTypeName##Iter mapTypeName##Iter; \
971739a20eSAndy Ritger typedef union mapTypeName mapTypeName
981739a20eSAndy Ritger
991739a20eSAndy Ritger /**
1001739a20eSAndy Ritger * @brief Internal node structure to embed within intrusive map values.
1011739a20eSAndy Ritger */
1021739a20eSAndy Ritger typedef struct MapNode MapNode;
1031739a20eSAndy Ritger
1041739a20eSAndy Ritger /**
1051739a20eSAndy Ritger * @brief Base type common to both intrusive and non-intrusive variants.
1061739a20eSAndy Ritger */
1071739a20eSAndy Ritger typedef struct MapBase MapBase;
1081739a20eSAndy Ritger
1091739a20eSAndy Ritger /**
1101739a20eSAndy Ritger * @brief Non-intrusive map (container-managed memory).
1111739a20eSAndy Ritger */
1121739a20eSAndy Ritger typedef struct NonIntrusiveMap NonIntrusiveMap;
1131739a20eSAndy Ritger
1141739a20eSAndy Ritger /**
1151739a20eSAndy Ritger * @brief Intrusive map (user-managed memory).
1161739a20eSAndy Ritger */
1171739a20eSAndy Ritger typedef struct IntrusiveMap IntrusiveMap;
1181739a20eSAndy Ritger
1191739a20eSAndy Ritger /**
1201739a20eSAndy Ritger * @brief Iterator over a range of map values.
1211739a20eSAndy Ritger *
1221739a20eSAndy Ritger * See @ref iterators for usage details.
1231739a20eSAndy Ritger */
1241739a20eSAndy Ritger typedef struct MapIterBase MapIterBase;
1251739a20eSAndy Ritger
1261739a20eSAndy Ritger struct MapNode
1271739a20eSAndy Ritger {
1281739a20eSAndy Ritger /// @privatesection
1291739a20eSAndy Ritger NvU64 key;
1301739a20eSAndy Ritger MapNode *pParent;
1311739a20eSAndy Ritger MapNode *pLeft;
1321739a20eSAndy Ritger MapNode *pRight;
1331739a20eSAndy Ritger NvBool bIsRed;
1341739a20eSAndy Ritger #if PORT_IS_CHECKED_BUILD
1351739a20eSAndy Ritger MapBase *pMap;
1361739a20eSAndy Ritger #endif
1371739a20eSAndy Ritger };
1381739a20eSAndy Ritger
1391739a20eSAndy Ritger struct MapIterBase
1401739a20eSAndy Ritger {
1411739a20eSAndy Ritger void *pValue;
1421739a20eSAndy Ritger MapBase *pMap;
1431739a20eSAndy Ritger MapNode *pNode;
1441739a20eSAndy Ritger MapNode *pLast;
1451739a20eSAndy Ritger #if PORT_IS_CHECKED_BUILD
1461739a20eSAndy Ritger NvU32 versionNumber;
147*b5bf85a8SAndy Ritger NvBool bValid;
1481739a20eSAndy Ritger #endif
1491739a20eSAndy Ritger };
1501739a20eSAndy Ritger
1511739a20eSAndy Ritger MapIterBase mapIterRange_IMPL(MapBase *pMap, void *pFirst, void *pLast);
1521739a20eSAndy Ritger CONT_VTABLE_DECL(MapBase, MapIterBase);
1531739a20eSAndy Ritger
1541739a20eSAndy Ritger struct MapBase
1551739a20eSAndy Ritger {
1561739a20eSAndy Ritger CONT_VTABLE_FIELD(MapBase);
1571739a20eSAndy Ritger MapNode *pRoot;
1581739a20eSAndy Ritger NvS32 nodeOffset;
1591739a20eSAndy Ritger NvU32 count;
1601739a20eSAndy Ritger #if PORT_IS_CHECKED_BUILD
1611739a20eSAndy Ritger NvU32 versionNumber;
1621739a20eSAndy Ritger #endif
1631739a20eSAndy Ritger };
1641739a20eSAndy Ritger
1651739a20eSAndy Ritger struct NonIntrusiveMap
1661739a20eSAndy Ritger {
1671739a20eSAndy Ritger MapBase base;
1681739a20eSAndy Ritger PORT_MEM_ALLOCATOR *pAllocator;
1691739a20eSAndy Ritger NvU32 valueSize;
1701739a20eSAndy Ritger };
1711739a20eSAndy Ritger
1721739a20eSAndy Ritger struct IntrusiveMap
1731739a20eSAndy Ritger {
1741739a20eSAndy Ritger MapBase base;
1751739a20eSAndy Ritger };
1761739a20eSAndy Ritger
1771739a20eSAndy Ritger #define mapInit(pMap, pAllocator) \
1781739a20eSAndy Ritger mapInit_IMPL(&((pMap)->real), pAllocator, sizeof(*(pMap)->valueSize))
1791739a20eSAndy Ritger
1801739a20eSAndy Ritger #define mapInitIntrusive(pMap) \
1811739a20eSAndy Ritger mapInitIntrusive_IMPL(&((pMap)->real), sizeof(*(pMap)->nodeOffset))
1821739a20eSAndy Ritger
1831739a20eSAndy Ritger #define mapDestroy(pMap) \
1841739a20eSAndy Ritger CONT_DISPATCH_ON_KIND(pMap, \
1851739a20eSAndy Ritger mapDestroy_IMPL((NonIntrusiveMap*)&((pMap)->real)), \
1861739a20eSAndy Ritger mapDestroyIntrusive_IMPL(&((pMap)->real.base)), \
1871739a20eSAndy Ritger contDispatchVoid_STUB())
1881739a20eSAndy Ritger
1891739a20eSAndy Ritger #define mapCount(pMap) \
1901739a20eSAndy Ritger mapCount_IMPL(&((pMap)->real).base)
1911739a20eSAndy Ritger
1921739a20eSAndy Ritger #define mapKey(pMap, pValue) \
1931739a20eSAndy Ritger mapKey_IMPL(&((pMap)->real).base, pValue)
1941739a20eSAndy Ritger
1951739a20eSAndy Ritger #define mapInsertNew(pMap, key) \
19694eaea97SAndy Ritger CONT_CAST_ELEM(pMap, mapInsertNew_IMPL(&(pMap)->real, key), mapIsValid_IMPL)
1971739a20eSAndy Ritger
1981739a20eSAndy Ritger #define mapInsertValue(pMap, key, pValue) \
1991739a20eSAndy Ritger CONT_CAST_ELEM(pMap, \
2001739a20eSAndy Ritger mapInsertValue_IMPL(&(pMap)->real, key, \
20194eaea97SAndy Ritger CONT_CHECK_ARG(pMap, pValue)), mapIsValid_IMPL)
2021739a20eSAndy Ritger
2031739a20eSAndy Ritger #define mapInsertExisting(pMap, key, pValue) \
2041739a20eSAndy Ritger mapInsertExisting_IMPL(&(pMap)->real, key, \
2051739a20eSAndy Ritger CONT_CHECK_ARG(pMap, pValue))
2061739a20eSAndy Ritger
2071739a20eSAndy Ritger #define mapRemove(pMap, pValue) \
2081739a20eSAndy Ritger CONT_DISPATCH_ON_KIND(pMap, \
2091739a20eSAndy Ritger mapRemove_IMPL((NonIntrusiveMap*)&((pMap)->real), \
2101739a20eSAndy Ritger CONT_CHECK_ARG(pMap, pValue)), \
2111739a20eSAndy Ritger mapRemoveIntrusive_IMPL(&((pMap)->real).base, \
2121739a20eSAndy Ritger CONT_CHECK_ARG(pMap, pValue)), \
2131739a20eSAndy Ritger contDispatchVoid_STUB())
2141739a20eSAndy Ritger
2151739a20eSAndy Ritger #define mapClear(pMap) \
2161739a20eSAndy Ritger mapDestroy(pMap)
2171739a20eSAndy Ritger
2181739a20eSAndy Ritger #define mapRemoveByKey(pMap, key) \
2191739a20eSAndy Ritger CONT_DISPATCH_ON_KIND(pMap, \
2201739a20eSAndy Ritger mapRemoveByKey_IMPL((NonIntrusiveMap*)&((pMap)->real), key), \
2211739a20eSAndy Ritger mapRemoveByKeyIntrusive_IMPL(&((pMap)->real).base, key), \
2221739a20eSAndy Ritger contDispatchVoid_STUB())
2231739a20eSAndy Ritger
2241739a20eSAndy Ritger #define mapFind(pMap, key) \
22594eaea97SAndy Ritger CONT_CAST_ELEM(pMap, mapFind_IMPL(&((pMap)->real).base, key), mapIsValid_IMPL)
2261739a20eSAndy Ritger
2271739a20eSAndy Ritger #define mapFindGEQ(pMap, keyMin) \
2281739a20eSAndy Ritger CONT_CAST_ELEM(pMap, \
22994eaea97SAndy Ritger mapFindGEQ_IMPL(&((pMap)->real).base, keyMin), mapIsValid_IMPL)
2301739a20eSAndy Ritger
2311739a20eSAndy Ritger #define mapFindLEQ(pMap, keyMax) \
2321739a20eSAndy Ritger CONT_CAST_ELEM(pMap, \
23394eaea97SAndy Ritger mapFindLEQ_IMPL(&((pMap)->real).base, keyMax), mapIsValid_IMPL)
2341739a20eSAndy Ritger
2351739a20eSAndy Ritger #define mapNext(pMap, pValue) \
2361739a20eSAndy Ritger CONT_CAST_ELEM(pMap, \
2371739a20eSAndy Ritger mapNext_IMPL(&((pMap)->real).base, \
23894eaea97SAndy Ritger CONT_CHECK_ARG(pMap, pValue)), mapIsValid_IMPL)
2391739a20eSAndy Ritger
2401739a20eSAndy Ritger #define mapPrev(pMap, pValue) \
2411739a20eSAndy Ritger CONT_CAST_ELEM(pMap, \
2421739a20eSAndy Ritger mapPrev_IMPL(&((pMap)->real).base, \
24394eaea97SAndy Ritger CONT_CHECK_ARG(pMap, pValue)), mapIsValid_IMPL)
2441739a20eSAndy Ritger
2451739a20eSAndy Ritger #define mapIterAll(pMap) \
2461739a20eSAndy Ritger mapIterRange(pMap, mapFindGEQ(pMap, 0), mapFindLEQ(pMap, NV_U64_MAX))
2471739a20eSAndy Ritger
2481739a20eSAndy Ritger #define mapIterRange(pMap, pFirst, pLast) \
2491739a20eSAndy Ritger CONT_ITER_RANGE(pMap, &mapIterRange_IMPL, \
25094eaea97SAndy Ritger CONT_CHECK_ARG(pMap, pFirst), CONT_CHECK_ARG(pMap, pLast), mapIsValid_IMPL)
2511739a20eSAndy Ritger
2521739a20eSAndy Ritger #define mapIterNext(pIt) \
2531739a20eSAndy Ritger mapIterNext_IMPL(&((pIt)->iter))
2541739a20eSAndy Ritger
2551739a20eSAndy Ritger void mapInit_IMPL(NonIntrusiveMap *pMap,
2561739a20eSAndy Ritger PORT_MEM_ALLOCATOR *pAllocator, NvU32 valueSize);
2571739a20eSAndy Ritger void mapInitIntrusive_IMPL(IntrusiveMap *pMap, NvS32 nodeOffset);
2581739a20eSAndy Ritger void mapDestroy_IMPL(NonIntrusiveMap *pMap);
2591739a20eSAndy Ritger void mapDestroyIntrusive_IMPL(MapBase *pMap);
2601739a20eSAndy Ritger
2611739a20eSAndy Ritger NvU32 mapCount_IMPL(MapBase *pMap);
2621739a20eSAndy Ritger NvU64 mapKey_IMPL(MapBase *pMap, void *pValue);
2631739a20eSAndy Ritger
2641739a20eSAndy Ritger void *mapInsertNew_IMPL(NonIntrusiveMap *pMap, NvU64 key);
265eb5c7665SAndy Ritger void *mapInsertValue_IMPL(NonIntrusiveMap *pMap, NvU64 key, const void *pValue);
2661739a20eSAndy Ritger NvBool mapInsertExisting_IMPL(IntrusiveMap *pMap, NvU64 key, void *pValue);
2671739a20eSAndy Ritger void mapRemove_IMPL(NonIntrusiveMap *pMap, void *pValue);
2681739a20eSAndy Ritger void mapRemoveIntrusive_IMPL(MapBase *pMap, void *pValue);
2691739a20eSAndy Ritger void mapRemoveByKey_IMPL(NonIntrusiveMap *pMap, NvU64 key);
2701739a20eSAndy Ritger void mapRemoveByKeyIntrusive_IMPL(MapBase *pMap, NvU64 key);
2711739a20eSAndy Ritger
2721739a20eSAndy Ritger void *mapFind_IMPL(MapBase *pMap, NvU64 key);
2731739a20eSAndy Ritger void *mapFindGEQ_IMPL(MapBase *pMap, NvU64 keyMin);
2741739a20eSAndy Ritger void *mapFindLEQ_IMPL(MapBase *pMap, NvU64 keyMax);
2751739a20eSAndy Ritger void *mapNext_IMPL(MapBase *pMap, void *pValue);
2761739a20eSAndy Ritger void *mapPrev_IMPL(MapBase *pMap, void *pValue);
2771739a20eSAndy Ritger
2781739a20eSAndy Ritger MapIterBase mapIterAll_IMPL(MapBase *pMap);
2791739a20eSAndy Ritger NvBool mapIterNext_IMPL(MapIterBase *pIt);
2801739a20eSAndy Ritger
2811739a20eSAndy Ritger static NV_FORCEINLINE MapNode *
mapValueToNode(MapBase * pMap,void * pValue)2821739a20eSAndy Ritger mapValueToNode(MapBase *pMap, void *pValue)
2831739a20eSAndy Ritger {
2841739a20eSAndy Ritger if (NULL == pMap) return NULL;
2851739a20eSAndy Ritger if (NULL == pValue) return NULL;
2861739a20eSAndy Ritger return (MapNode*)((NvU8*)pValue + pMap->nodeOffset);
2871739a20eSAndy Ritger }
2881739a20eSAndy Ritger
2891739a20eSAndy Ritger static NV_FORCEINLINE void *
mapNodeToValue(MapBase * pMap,MapNode * pNode)2901739a20eSAndy Ritger mapNodeToValue(MapBase *pMap, MapNode *pNode)
2911739a20eSAndy Ritger {
2921739a20eSAndy Ritger if (NULL == pMap) return NULL;
2931739a20eSAndy Ritger if (NULL == pNode) return NULL;
2941739a20eSAndy Ritger return (NvU8*)pNode - pMap->nodeOffset;
2951739a20eSAndy Ritger }
2961739a20eSAndy Ritger
29794eaea97SAndy Ritger NvBool mapIsValid_IMPL(void *pMap);
29894eaea97SAndy Ritger
2991739a20eSAndy Ritger #ifdef __cplusplus
3001739a20eSAndy Ritger }
3011739a20eSAndy Ritger #endif
3021739a20eSAndy Ritger
3031739a20eSAndy Ritger #endif // _NV_CONTAINERS_MAP_H_
304