carb/variant/VariantTypes.h

File members: carb/variant/VariantTypes.h

// Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//

#pragma once

#include "../RString.h"
#include "../IObject.h"
#include "../../omni/String.h"
#include "../../omni/detail/PointerIterator.h"

namespace carb
{
namespace variant
{

constexpr RString eNull{ carb::eRString::RS_null };
constexpr RString eBool{ carb::eRString::RS_bool };
constexpr RString eUInt8{ carb::eRString::RS_uint8 };
constexpr RString eUInt16{ carb::eRString::RS_uint16 };
constexpr RString eUInt32{ carb::eRString::RS_uint32 };
constexpr RString eUInt64{ carb::eRString::RS_uint64 };
constexpr RString eInt8{ carb::eRString::RS_int8 };
constexpr RString eInt16{ carb::eRString::RS_int16 };
constexpr RString eInt32{ carb::eRString::RS_int32 };
constexpr RString eInt64{ carb::eRString::RS_int64 };
constexpr RString eFloat{ carb::eRString::RS_float };
constexpr RString eDouble{ carb::eRString::RS_double };
constexpr RString eString{ carb::eRString::RS_string };
constexpr RString eCharPtr{ carb::eRString::RS_charptr };
constexpr RString eDictionary{ carb::eRString::RS_dictionary };
constexpr RString eVariantPair{ carb::eRString::RS_variant_pair };
constexpr RString eVariantArray{ carb::eRString::RS_variant_array };
constexpr RString eVariantMap{ carb::eRString::RS_variant_map };
constexpr RString eRString{ carb::eRString::RS_RString };
constexpr RString eRStringU{ carb::eRString::RS_RStringU };
constexpr RString eRStringKey{ carb::eRString::RS_RStringKey };
constexpr RString eRStringUKey{ carb::eRString::RS_RStringUKey };

struct VTable;
class Variant;

struct VariantData
{
    const VTable* vtable;

    void* data;
};
CARB_ASSERT_INTEROP_SAFE(VariantData);

struct VTable
{
    uint32_t sizeOf;

    RString typeName;

    void (*Destructor)(VariantData* self) noexcept;

    VariantData (*Copy)(const VariantData* self) noexcept;

    bool (*Equals)(const VariantData* self, const VariantData* other) noexcept;

    omni::string (*ToString)(const VariantData* self) noexcept;

    bool (*ConvertTo)(const VariantData* self, const VTable* newtype, VariantData* out) noexcept;

    size_t (*Hash)(const VariantData* self) noexcept;

    // Note to maintainers: adding new functions here does not necessarily require a version change for IVariant. Add a
    // `struct traits` function that performs a default behavior if the function is `nullptr` or if the `sizeOf` is less
    // than the offset of your new member. All calls to the v-table function should happen in the new `traits` function.
};
CARB_ASSERT_INTEROP_SAFE(VTable);

class VariantArray : public IObject
{
public:
    using iterator = omni::detail::PointerIterator<Variant*, VariantArray>;

    using const_iterator = omni::detail::PointerIterator<const Variant*, VariantArray>;

    virtual Variant* data() noexcept = 0;

    virtual const Variant* data() const noexcept = 0;

    virtual size_t size() const noexcept = 0;

    virtual void push_back(Variant v) noexcept = 0;

    virtual bool insert(size_t offset, Variant v) noexcept = 0;

    virtual bool erase(size_t offset) noexcept = 0;

    virtual bool pop_back() noexcept = 0;

    virtual void assign(const Variant* p, size_t count) noexcept = 0;

    virtual void reserve(size_t count) noexcept = 0;

    virtual void resize(size_t count) noexcept = 0;

    virtual size_t capacity() const noexcept = 0;

    void clear() noexcept;

    bool empty() const noexcept;

    Variant& at(size_t index);

    const Variant& at(size_t index) const;

    Variant& operator[](size_t index) noexcept;

    const Variant& operator[](size_t index) const noexcept;

    Variant& front() noexcept;

    const Variant& front() const noexcept;

    Variant& back() noexcept;

    const Variant& back() const noexcept;

    iterator begin() noexcept;

    iterator end() noexcept;

    const_iterator begin() const noexcept;

    const_iterator end() const noexcept;
};
using VariantArrayPtr = ObjectPtr<VariantArray>;

struct KeyValuePair;

class VariantMap : public IObject
{
public:
    using key_type = Variant;
    using mapped_type = Variant;
    using value_type = KeyValuePair;
    using size_type = size_t;
    using difference_type = ptrdiff_t;
    using reference = value_type&;
    using const_reference = const value_type&;
    using pointer = value_type*;
    using const_pointer = const value_type*;

    // clang-format off
#ifndef DOXYGEN_SHOULD_SKIP_THIS
private:
    class iter_base
    {
    public:
        constexpr iter_base() noexcept = default;
        bool operator == (const iter_base& other) const noexcept { CARB_ASSERT(owner == other.owner); return where == other.where; }
        bool operator != (const iter_base& other) const noexcept { CARB_ASSERT(owner == other.owner); return where != other.where; }
    protected:
        constexpr iter_base(const VariantMap* owner_, pointer where_) noexcept : owner(owner_), where(where_) {}
        const VariantMap* owner{ nullptr };
        pointer where{ nullptr };
    };
public:
    class const_find_iterator : public iter_base
    {
        using Base = iter_base;
    public:
        using iterator_category = std::forward_iterator_tag;
        using value_type = VariantMap::value_type;
        using difference_type = VariantMap::difference_type;
        using pointer = VariantMap::const_pointer;
        using reference = VariantMap::const_reference;
        constexpr               const_find_iterator() noexcept = default;
        reference               operator *  () const noexcept   { CARB_ASSERT(this->where); return *this->where; }
        pointer                 operator -> () const noexcept   { CARB_ASSERT(this->where); return this->where; }
        const_find_iterator&    operator ++ () noexcept         { incr(); return *this; }
        const_find_iterator     operator ++ (int) noexcept      { const_find_iterator i{ *this }; incr(); return i; }
    protected:
        friend class VariantMap;
        constexpr const_find_iterator(const VariantMap* owner_, value_type* where_) noexcept : Base(owner_, where_) {}
        void incr() { CARB_ASSERT(this->owner && this->where); this->where = this->owner->findNext(this->where); }
    };
    class find_iterator : public const_find_iterator
    {
        using Base = const_find_iterator;
    public:
        using iterator_category = std::forward_iterator_tag;
        using value_type = VariantMap::value_type;
        using difference_type = VariantMap::difference_type;
        using pointer = VariantMap::pointer;
        using reference = VariantMap::reference;
        constexpr       find_iterator() noexcept = default;
        reference       operator *  () const noexcept   { CARB_ASSERT(this->where); return *this->where; }
        pointer         operator -> () const noexcept   { CARB_ASSERT(this->where); return this->where; }
        find_iterator&  operator ++ () noexcept         { this->incr(); return *this; }
        find_iterator   operator ++ (int) noexcept      { find_iterator i{ *this }; this->incr(); return i; }
    protected:
        friend class VariantMap;
        constexpr find_iterator(const VariantMap* owner_, value_type* where_) noexcept : Base(owner_, where_) {}
    };

    class const_iterator : public iter_base
    {
        using Base = iter_base;
    public:
        using iterator_category = std::forward_iterator_tag;
        using value_type = VariantMap::value_type;
        using difference_type = VariantMap::difference_type;
        using pointer = VariantMap::const_pointer;
        using reference = VariantMap::const_reference;
        constexpr       const_iterator() noexcept = default;
        reference       operator *  () const noexcept   { CARB_ASSERT(this->where); return *this->where; }
        pointer         operator -> () const noexcept   { CARB_ASSERT(this->where); return this->where; }
        const_iterator& operator ++ () noexcept         { incr(); return *this;}
        const_iterator  operator ++ (int) noexcept      { const_iterator i{ *this }; incr(); return i; }
    protected:
        friend class VariantMap;
        constexpr const_iterator(const VariantMap* owner_, value_type* where_) noexcept : Base{ owner_, where_ } {}
        void incr() { CARB_ASSERT(this->owner && this->where); this->where = this->owner->iterNext(this->where); }
    };
    class iterator : public const_iterator
    {
        using Base = const_iterator;
    public:
        using iterator_category = std::forward_iterator_tag;
        using value_type = VariantMap::value_type;
        using difference_type = VariantMap::difference_type;
        using pointer = VariantMap::pointer;
        using reference = VariantMap::reference;
        constexpr   iterator() noexcept = default;
        reference   operator *  () const noexcept   { CARB_ASSERT(this->where); return *this->where; }
        pointer     operator -> () const noexcept   { CARB_ASSERT(this->where); return this->where; }
        iterator&   operator ++ () noexcept         { this->incr(); return *this; }
        iterator    operator ++ (int) noexcept      { iterator i{ *this }; this->incr(); return i; }
    protected:
        friend class VariantMap;
        constexpr iterator(const VariantMap* owner_, value_type* where_) noexcept : Base(owner_, where_) {}
    };
#endif
    // clang-format on

    const_iterator cbegin() const noexcept;

    const_iterator begin() const noexcept;

    iterator begin() noexcept;

    const_iterator cend() const noexcept;

    const_iterator end() const noexcept;

    iterator end() noexcept;

    bool empty() const noexcept;

    virtual size_t size() const noexcept = 0;

    std::pair<iterator, bool> insert(const Variant& key, Variant value);

    size_t erase(const Variant& key) noexcept;

    iterator erase(const_iterator pos) noexcept;

    find_iterator erase(const_find_iterator pos) noexcept;

    find_iterator find(const Variant& key) noexcept;

    const_find_iterator find(const Variant& key) const noexcept;

    bool contains(const Variant& key) const noexcept;

    size_t count(const Variant& key) const noexcept;

#if CARB_EXCEPTIONS_ENABLED || defined(DOXYGEN_BUILD)
    mapped_type& at(const Variant& key);

    const mapped_type& at(const Variant& key) const;
#endif

    mapped_type& operator[](const Variant& key);

    virtual void clear() noexcept = 0;

    virtual size_t capacity() const noexcept = 0;

    virtual void reserve(size_t n) noexcept = 0;

    virtual void rehash(size_t n) noexcept = 0;

private:
    virtual KeyValuePair* internalInsert(const Variant& key, bool& success) noexcept = 0;
    virtual void internalErase(const KeyValuePair*) noexcept = 0;
    virtual KeyValuePair* internalFind(const Variant& key) const noexcept = 0;
    virtual KeyValuePair* internalBegin() const noexcept = 0;
    virtual KeyValuePair* iterNext(KeyValuePair*) const noexcept = 0;
    virtual KeyValuePair* findNext(KeyValuePair*) const noexcept = 0;
};
using VariantMapPtr = ObjectPtr<VariantMap>;

template <class T, class Enable = void>
struct Translator;

} // namespace variant
} // namespace carb