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