IDictionary2.h#

Fully qualified name: carb/dictionary/detail/IDictionary2.h

File members: carb/dictionary/detail/IDictionary2.h

// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: LicenseRef-NvidiaProprietary
//
// NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
// property and proprietary rights in and to this material, related
// documentation and any modifications thereto. Any use, reproduction,
// disclosure or distribution of this material and related documentation
// without an express license agreement from NVIDIA CORPORATION or
// its affiliates is strictly prohibited.

#pragma once

#ifndef carb_dictionary_IDictionary_latest
#    error Must include via ../IDictionary.h
#endif

#if !CARB_VERSION_ATLEAST(carb_dictionary_IDictionary, 2, 0)
#    error Version too low to be included
#endif

#include "../../../omni/String.h"
#include "../../cpp/Span.h"

namespace carb::dictionary
{

#ifndef DOXYGEN_BUILD
inline namespace v2
{
#endif
class IDictionary
{
public:
    CARB_PLUGIN_INTERFACE_EX("carb::dictionary::IDictionary",
                             carb_dictionary_IDictionary_latest,
                             carb_dictionary_IDictionary)

    virtual const Item* getItem(const Item* baseItem, cpp::string_view path) const = 0;

    virtual Item* getItem(Item* baseItem, cpp::string_view path) const = 0;

    virtual size_t getItemChildCount(const Item* item) const = 0;

    virtual const Item* getItemChildByIndex(const Item* item, size_t childIndex) const = 0;

    virtual Item* getItemChildByIndex(Item* item, size_t childIndex) const = 0;

    virtual const Item* getItemParent(const Item* item) const = 0;

    virtual Item* getItemParent(Item* item) const = 0;

    virtual ItemType getItemType(const Item* item) const = 0;

    virtual cpp::optional<omni::string> createStringFromItemName(const Item* item) const = 0;

    virtual cpp::optional<cpp::zstring_view> getItemName(const Item* item) const = 0;

    virtual Item* createItem(Item* baseItem, cpp::string_view path, ItemType itemType) const = 0;

    virtual bool isAccessibleAs(ItemType itemType, const Item* item) const = 0;

    virtual int64_t getAsInt64(const Item* item) const = 0;

    virtual void setInt64(Item* item, int64_t value) const = 0;

    virtual double getAsFloat64(const Item* item) const = 0;

    virtual void setFloat64(Item* item, double value) const = 0;

    virtual bool getAsBool(const Item* item) const = 0;

    virtual void setBool(Item* item, bool value) const = 0;

    virtual cpp::optional<omni::string> createStringFromItemValue(const Item* item) const = 0;

    virtual cpp::optional<cpp::zstring_view> getStringView(const Item* item) const = 0;

    virtual cpp::optional<omni::string> getString(const Item* item) const = 0;

    virtual void setString(Item* item, cpp::string_view value) const = 0;

    virtual bool isAccessibleAsArray(const Item* item) const = 0;

    virtual bool isAccessibleAsArrayOf(ItemType itemType, const Item* item) const = 0;

    virtual size_t getArrayLength(const Item* item) const = 0;

    virtual ItemType getPreferredArrayType(const Item* item) const = 0;

    virtual int64_t getAsInt64At(const Item* item, size_t index) const = 0;

    virtual void setInt64At(Item* item, size_t index, int64_t value) const = 0;

    virtual size_t getAsInt64Array(const Item* item, int64_t* arrayOut, size_t arrayBufferLength) const = 0;

    virtual void setInt64Array(Item* item, const cpp::span<const int64_t> array) const = 0;

    virtual size_t getAsIntArray(const Item* item, int32_t* arrayOut, size_t arrayBufferLength) const = 0;

    virtual void setIntArray(Item* item, const cpp::span<const int32_t> array) const = 0;

    virtual double getAsFloat64At(const Item* item, size_t index) const = 0;

    virtual void setFloat64At(Item* item, size_t index, double value) const = 0;

    virtual size_t getAsFloat64Array(const Item* item, double* arrayOut, size_t arrayBufferLength) const = 0;

    virtual void setFloat64Array(Item* item, const cpp::span<const double> array) const = 0;

    virtual size_t getAsFloatArray(const Item* item, float* arrayOut, size_t arrayBufferLength) const = 0;

    virtual void setFloatArray(Item* item, const cpp::span<const float> array) const = 0;

    virtual bool getAsBoolAt(const Item* item, size_t index) const = 0;

    virtual void setBoolAt(Item* item, size_t index, bool value) const = 0;

    virtual size_t getAsBoolArray(const Item* item, bool* arrayOut, size_t arrayBufferLength) const = 0;

    virtual void setBoolArray(Item* item, const cpp::span<const bool> array) const = 0;

    virtual cpp::optional<omni::string> createStringFromItemValueAt(const Item* item, size_t index) const = 0;

    virtual cpp::optional<cpp::zstring_view> getStringViewAt(const Item* item, size_t index) const = 0;

    virtual void setStringAt(Item* item, size_t index, cpp::string_view value) const = 0;

    virtual size_t getStringArray(const Item* item, cpp::string_view* arrayOut, size_t arrayBufferLength) const = 0;

    virtual void setStringArray(Item* item, const cpp::span<const cpp::string_view> array) const = 0;

    virtual const Item* getItemAt(const Item* item, size_t index) const = 0;

    virtual Item* getItemAt(Item* item, size_t index) const = 0;

    virtual size_t getItemArray(const Item* item, const Item** arrayOut, size_t arrayBufferLength) const = 0;

    virtual void update(Item* dstBaseItem,
                        cpp::string_view dstPath,
                        const Item* srcBaseItem,
                        cpp::string_view srcPath,
                        OnUpdateItemFn onUpdateItemFn,
                        void* userData) const = 0;

    virtual void destroyItem(Item* item) const = 0;

    virtual bool getItemFlag(const Item* item, ItemFlag flag) const = 0;

    virtual void setItemFlag(Item* item, ItemFlag flag, bool flagValue) const = 0;

    virtual SubscriptionId* subscribeToNodeChangeEvents(Item* baseItem,
                                                        cpp::string_view path,
                                                        OnNodeChangeEventFn onChangeEventFn,
                                                        void* userData) const = 0;

    virtual SubscriptionId* subscribeToTreeChangeEvents(Item* baseItem,
                                                        cpp::string_view path,
                                                        OnTreeChangeEventFn onChangeEventFn,
                                                        void* userData) const = 0;

    virtual void unsubscribeFromChangeEvents(SubscriptionId* subscriptionId) const = 0;

    virtual void unsubscribeItemFromNodeChangeEvents(Item* item) const = 0;

    virtual void unsubscribeItemFromTreeChangeEvents(Item* item) const = 0;

    virtual void readLock(const Item* item) const = 0;

    virtual void writeLock(Item* item) const = 0;

    virtual void unlock(const Item* item) const = 0;

    virtual const extras::hash128_t getHash(const Item* item) const = 0;

    virtual int lexicographicalCompare(const Item* itemA, const Item* itemB) const = 0;

    // ^ Interface functions
    // v Helper functions

    int32_t getAsInt(const Item* item) const;

    void setInt(Item* item, int32_t value) const;

    Item* makeInt64AtPath(Item* baseItem, cpp::string_view path, int64_t value) const;

    Item* makeIntAtPath(Item* baseItem, cpp::string_view path, int32_t value) const;

    float getAsFloat(const Item* item) const;

    void setFloat(Item* item, float value) const;

    Item* makeFloat64AtPath(Item* baseItem, cpp::string_view path, double value) const;

    Item* makeFloatAtPath(Item* baseItem, cpp::string_view path, float value) const;

    Item* makeBoolAtPath(Item* baseItem, cpp::string_view path, bool value) const;

    Item* makeStringAtPath(Item* baseItem, cpp::string_view path, cpp::string_view value) const;

    Item* makeDictionaryAtPath(Item* parentItem, cpp::string_view path) const;

    template <typename T>
    T get(const Item* item) const = delete;

    template <typename T, typename U = T>
    T get(const Item* baseItem, cpp::string_view path, U&& defaultValue = T{}) const;

    template <typename T>
    cpp::optional<T> getOpt(const Item* baseItem, cpp::string_view path) const;

    template <typename T, std::enable_if_t<!carb::cpp::is_std_string_view_like_v<T>, bool> = true>
    Item* makeAtPath(Item* baseItem, cpp::string_view path, T value) const;

    Item* makeAtPath(Item* baseItem, cpp::string_view path, cpp::string_view value) const;

    int32_t getAsIntAt(const Item* item, size_t index) const;

    void setIntAt(Item* item, size_t index, int32_t value) const;

    float getAsFloatAt(const Item* item, size_t index) const;

    void setFloatAt(Item* item, size_t index, float value) const;

    template <typename ArrayElementType>
    void setArray(Item* item, const cpp::span<const ArrayElementType> array) const = delete;

    void deleteChildren(Item* item) const;

    void copyItemFlags(Item* dstItem, const Item* srcItem) const;

    Item* duplicateItem(const Item* item) const
    {
        return duplicateItem(item, nullptr, {});
    }

    virtual Item* duplicateItem(const Item* item, Item* newParent, cpp::string_view newKey) const = 0;
};

#define CARBLOCAL_CONST const
#include "IDictionaryCommon.h"
#undef CARBLOCAL_CONST

inline Item* IDictionary::makeIntAtPath(Item* baseItem, cpp::string_view path, int32_t value) const
{
    return makeInt64AtPath(baseItem, path, value);
}

inline Item* IDictionary::makeFloatAtPath(Item* baseItem, cpp::string_view path, float value) const
{
    return makeFloat64AtPath(baseItem, path, value);
}

inline Item* IDictionary::makeInt64AtPath(Item* parentItem, cpp::string_view path, int64_t value) const
{
    ScopedWrite g(*this, parentItem);
    Item* item = getItem(parentItem, path);
    if (!item)
    {
        item = createItem(parentItem, path, ItemType::eInt);
    }
    setInt64(item, value);
    return item;
}

inline Item* IDictionary::makeFloat64AtPath(Item* parentItem, cpp::string_view path, double value) const
{
    ScopedWrite g(*this, parentItem);
    Item* item = getItem(parentItem, path);
    if (!item)
    {
        item = createItem(parentItem, path, ItemType::eFloat);
    }
    setFloat64(item, value);
    return item;
}

inline Item* IDictionary::makeBoolAtPath(Item* parentItem, cpp::string_view path, bool value) const
{
    ScopedWrite g(*this, parentItem);
    Item* item = getItem(parentItem, path);
    if (!item)
    {
        item = createItem(parentItem, path, ItemType::eBool);
    }
    setBool(item, value);
    return item;
}

inline Item* IDictionary::makeStringAtPath(Item* parentItem, cpp::string_view path, cpp::string_view value) const
{
    ScopedWrite g(*this, parentItem);
    Item* item = getItem(parentItem, path);
    if (!item)
    {
        item = createItem(parentItem, path, ItemType::eString);
    }
    setString(item, value);
    return item;
}

inline Item* IDictionary::makeDictionaryAtPath(Item* parentItem, cpp::string_view path) const
{
    ScopedWrite g(*this, parentItem);
    Item* item = getItem(parentItem, path);
    if (!item)
    {
        item = createItem(parentItem, path, ItemType::eDictionary);
        return item;
    }
    ItemType itemType = getItemType(item);
    if (itemType != ItemType::eDictionary)
    {
        // Bit of a hack to change to a dictionary without deleting the node
        setBoolArray(item, {});
        CARB_ASSERT(getItemType(item) == ItemType::eDictionary);
    }
    return item;
}

#ifndef DOXYGEN_BUILD
template <>
inline cpp::optional<cpp::zstring_view> IDictionary::get<cpp::optional<cpp::zstring_view>>(const Item* item) const
{
    return getStringView(item);
}

template <>
inline cpp::zstring_view IDictionary::get<cpp::zstring_view>(const Item* item) const
{
    return getStringView(item).value_or("");
}

template <>
inline std::string IDictionary::get<std::string>(const Item* item) const
{
    ScopedRead read(*this, item);
    return std::string(getStringView(item).value_or(""));
}

template <>
inline cpp::optional<std::string> IDictionary::get<cpp::optional<std::string>>(const Item* item) const
{
    ScopedRead lock(*this, item);
    if (auto buf = getStringView(item))
        return std::string(*buf);
    return cpp::nullopt;
}

template <>
inline omni::string IDictionary::get<omni::string>(const Item* item) const
{
    return getString(item).value_or("");
}

template <>
inline cpp::optional<omni::string> IDictionary::get<cpp::optional<omni::string>>(const Item* item) const
{
    return getString(item);
}

template <class T, class U>
inline T IDictionary::get(const Item* baseItem, cpp::string_view path, U&& defaultValue) const
{
    ScopedRead read(*this, baseItem);
    if (auto item = getItem(baseItem, path))
        return get<T>(item);
    return T(std::forward<U>(defaultValue));
}

template <class T>
inline cpp::optional<T> IDictionary::getOpt(const Item* baseItem, cpp::string_view path) const
{
    ScopedRead read(*this, baseItem);
    if (auto item = getItem(baseItem, path))
        return get<T>(item);
    return cpp::nullopt;
}

template <>
inline Item* IDictionary::makeAtPath<int32_t, true>(Item* baseItem, cpp::string_view path, int32_t value) const
{
    return makeIntAtPath(baseItem, path, value);
}

template <>
inline Item* IDictionary::makeAtPath<int64_t, true>(Item* baseItem, cpp::string_view path, int64_t value) const
{
    return makeInt64AtPath(baseItem, path, value);
}

template <>
inline Item* IDictionary::makeAtPath<float, true>(Item* baseItem, cpp::string_view path, float value) const
{
    return makeFloatAtPath(baseItem, path, value);
}

template <>
inline Item* IDictionary::makeAtPath<double, true>(Item* baseItem, cpp::string_view path, double value) const
{
    return makeFloat64AtPath(baseItem, path, value);
}

template <>
inline Item* IDictionary::makeAtPath<bool, true>(Item* baseItem, cpp::string_view path, bool value) const
{
    return makeBoolAtPath(baseItem, path, value);
}

template <>
inline Item* IDictionary::makeAtPath<Int2, true>(Item* baseItem, cpp::string_view path, Int2 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const int32_t array[] = { value.x, value.y };
    setIntArray(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Int3, true>(Item* baseItem, cpp::string_view path, Int3 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const int32_t array[] = { value.x, value.y, value.z };
    setIntArray(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Int4, true>(Item* baseItem, cpp::string_view path, Int4 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const int32_t array[] = { value.x, value.y, value.z, value.w };
    setIntArray(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Uint2, true>(Item* baseItem, cpp::string_view path, Uint2 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const int64_t array[] = { value.x, value.y };
    setInt64Array(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Uint3, true>(Item* baseItem, cpp::string_view path, Uint3 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const int64_t array[] = { value.x, value.y, value.z };
    setInt64Array(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Uint4, true>(Item* baseItem, cpp::string_view path, Uint4 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const int64_t array[] = { value.x, value.y, value.z, value.w };
    setInt64Array(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Float2, true>(Item* baseItem, cpp::string_view path, Float2 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const float array[] = { value.x, value.y };
    setFloatArray(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Float3, true>(Item* baseItem, cpp::string_view path, Float3 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const float array[] = { value.x, value.y, value.z };
    setFloatArray(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Float4, true>(Item* baseItem, cpp::string_view path, Float4 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const float array[] = { value.x, value.y, value.z, value.w };
    setFloatArray(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Double2, true>(Item* baseItem, cpp::string_view path, Double2 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const double array[] = { value.x, value.y };
    setFloat64Array(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Double3, true>(Item* baseItem, cpp::string_view path, Double3 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const double array[] = { value.x, value.y, value.z };
    setFloat64Array(item, cpp::span(array));
    return item;
}

template <>
inline Item* IDictionary::makeAtPath<Double4, true>(Item* baseItem, cpp::string_view path, Double4 value) const
{
    Item* item = baseItem;
    if (!path.empty())
    {
        item = makeDictionaryAtPath(baseItem, path);
    }
    const double array[] = { value.x, value.y, value.z, value.w };
    setFloat64Array(item, cpp::span(array));
    return item;
}

inline Item* IDictionary::makeAtPath(Item* baseItem, cpp::string_view path, cpp::string_view value) const
{
    return makeStringAtPath(baseItem, path, value);
}

template <>
inline void IDictionary::setArray(Item* baseItem, const cpp::span<const bool> array) const
{
    return setBoolArray(baseItem, array);
}

template <>
inline void IDictionary::setArray(Item* baseItem, const cpp::span<const int32_t> array) const
{
    return setIntArray(baseItem, array);
}

template <>
inline void IDictionary::setArray(Item* baseItem, const cpp::span<const int64_t> array) const
{
    return setInt64Array(baseItem, array);
}

template <>
inline void IDictionary::setArray(Item* baseItem, const cpp::span<const float> array) const
{
    return setFloatArray(baseItem, array);
}

template <>
inline void IDictionary::setArray(Item* baseItem, const cpp::span<const double> array) const
{
    return setFloat64Array(baseItem, array);
}

template <>
inline void IDictionary::setArray(Item* baseItem, const cpp::span<const cpp::string_view> array) const
{
    setStringArray(baseItem, array);
}

inline void IDictionary::deleteChildren(Item* item) const
{
    ScopedWrite g(*this, item);
    size_t childCount = getItemChildCount(item);
    while (childCount != 0)
        destroyItem(getItemChildByIndex(item, --childCount));
}

#endif // DOXYGEN_BUILD

#ifndef DOXYGEN_BUILD
} // namespace v2
#endif
} // namespace carb::dictionary