Program Listing for omni/graph/core/Handle.h

↰ Return to documentation for omni/graph/core/Handle.h

// Copyright (c) 2021-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 <omni/fabric/IPath.h>
#include <omni/fabric/IToken.h>
#include <omni/fabric/IFabric.h>
#include <omni/graph/core/TemplateUtils.h>

// Support for generic handles for interface objects.
// Ideally each of the handle types would be put into interface files for their corresponding types. In the
// current scheme they are too intertwined to separate them cleanly. Having this file provides a way for code
// to have access to handles for passing around without pulling in all of the unrelated interfaces.

namespace omni {
namespace graph {
namespace core {

#define STRUCT_INTEGRITY_CHECK(StructName, LastFunction, NumberOfFunctions)                             \
    static_assert(offsetof(StructName, LastFunction) == NumberOfFunctions * sizeof(void(*)()),          \
                  "New " # StructName " ABI methods must be added at the end");                         \
    static_assert(std::is_trivial<StructName>::value, # StructName " must be a POD");                   \
    static_assert(std::is_standard_layout<StructName>::value, # StructName " must have std layout");    \
    static_assert(sizeof(StructName) == (NumberOfFunctions+1) * sizeof(void (*)()),                     \
                  "Please update the integrity check macro to point to the last method of " #StructName);

// ==============================================================================================================
template <typename T, typename SUBCLASS>
class HandleBase
{
public:
    HandleBase() = default;
    HandleBase(const HandleBase&) = default;
    explicit HandleBase(const T& h) : handle(h)
    {
    }
    HandleBase& operator=(const HandleBase&) = default;
    explicit operator T() const
    {
        return handle;
    }
    bool isValid() const
    {
        return (handle != SUBCLASS::invalidValue());
    }
    bool operator==(HandleBase rhs) const
    {
        return handle == rhs.handle;
    }
    bool operator!=(HandleBase rhs) const
    {
        return !(handle == rhs.handle);
    }

    static constexpr SUBCLASS invalidHandle()
    {
        return static_cast<SUBCLASS>(SUBCLASS::invalidValue());
    }

protected:
    T handle;
};

using HandleInt = uint64_t;

using NameToken = omni::fabric::TokenC;

using TargetPath = omni::fabric::PathC;

using BucketId = omni::fabric::BucketId;

using ObjectId = HandleInt;

// NOTE: Due to Linux debug linking pre-C++17 not liking constexpr static variables,
//       other than built-in integer types, being passed by const reference,
//       invalid values for handles are now constructed via inline functions, instead
//       of using constexpr static variables.  Just to play it safe, we're using a macro
//       here, in case it also has an issue with built-in integer types being referenced
//       from an inline function at compile-time.  Note that the link errors don't show
//       up until *runtime*, since they appear to be handled via dynamic linking.
#define OG_INVALID_HANDLE_INT_VALUE (~HandleInt(0))
constexpr static HandleInt kInvalidHandleIntValue = OG_INVALID_HANDLE_INT_VALUE;

// ==============================================================================================================
using AttrKey = std::pair<HandleInt, HandleInt>;
struct AttrKeyHash
{
    std::size_t operator()(const AttrKey& attrKey) const
    {
        return std::hash<HandleInt>()(attrKey.first) ^ std::hash<HandleInt>()(attrKey.second);
    }
};

// ==============================================================================================================
class ConstAttributeDataHandle : public HandleBase<AttrKey, ConstAttributeDataHandle>
{
public:
    using HandleBase<AttrKey, ConstAttributeDataHandle>::HandleBase;

    omni::fabric::PathC path() const noexcept { return handle.first; }

    omni::fabric::TokenC name() const noexcept { return handle.second; }

    static constexpr AttrKey invalidValue()
    {
        return std::make_pair(HandleInt(omni::fabric::kUninitializedPath.path),
                              HandleInt(omni::fabric::kUninitializedToken.token));
    }
};

// --------------------------------------------------------------------------------------------------------------
struct ConstAttributeDataHandleHash
{
    std::size_t operator()(const ConstAttributeDataHandle& attrDataHandle) const
    {
        AttrKey attrKey(attrDataHandle);
        return AttrKeyHash()(attrKey);
    }
};

// --------------------------------------------------------------------------------------------------------------
class AttributeDataHandle : public HandleBase<AttrKey, AttributeDataHandle>
{
public:
    using HandleBase<AttrKey, AttributeDataHandle>::HandleBase;

    static constexpr AttrKey invalidValue()
    {
        return std::make_pair(HandleInt(omni::fabric::kUninitializedPath.path),
                              HandleInt(omni::fabric::kUninitializedToken.token));
    }

    omni::fabric::PathC path() const noexcept { return handle.first; }

    omni::fabric::TokenC name() const noexcept { return handle.second; }

    operator ConstAttributeDataHandle() const
    {
        return ConstAttributeDataHandle(AttrKey(*this));
    }
};

// ==============================================================================================================
class ConstBundleHandle : public HandleBase<HandleInt, ConstBundleHandle>
{
public:
    using HandleBase<HandleInt, ConstBundleHandle>::HandleBase;

    static constexpr HandleInt invalidValue()
    {
        return omni::fabric::kUninitializedPath.path;
    }
};

// --------------------------------------------------------------------------------------------------------------
struct ConstBundleHandleHash
{
    std::size_t operator()(const ConstBundleHandle& handle) const
    {
        return std::hash<HandleInt>()(HandleInt(handle));
    }
};

// --------------------------------------------------------------------------------------------------------------
class BundleHandle : public HandleBase<HandleInt, BundleHandle>
{
public:
    using HandleBase<HandleInt, BundleHandle>::HandleBase;

    static constexpr HandleInt invalidValue()
    {
        return omni::fabric::kUninitializedPath.path;
    }

    operator ConstBundleHandle() const
    {
        return ConstBundleHandle(HandleInt(*this));
    }
};

using ConstPrimHandle [[deprecated("Use ConstBundleHandle!")]]  = ConstBundleHandle;
using ConstPrimHandleHash [[deprecated("Use ConstBundleHandleHash!")]] = ConstBundleHandleHash;
using PrimHandle [[deprecated("Use BundleHandle!")]] = BundleHandle;

// ==============================================================================================================
class NodeContextHandle : public HandleBase<HandleInt, NodeContextHandle>
{
public:
    using HandleBase<HandleInt, NodeContextHandle>::HandleBase;

    static constexpr HandleInt invalidValue()
    {
        return kInvalidHandleIntValue;
    }
};

// ======================================================================
// Support for attributes
using AttributeHandle = uint64_t;
using AttributeHash = uint64_t;
static constexpr AttributeHandle kInvalidAttributeHandle = 0;
struct IAttribute;
struct AttributeObj
{
    const IAttribute* iAttribute;
    AttributeHandle attributeHandle;

    bool isValid() const
    {
        return iAttribute && (attributeHandle != kInvalidAttributeHandle);
    }
};

// ======================================================================
// Support for node types
using NodeTypeHandle = uint64_t;
static constexpr NodeTypeHandle kInvalidNodeTypeHandle = 0;
struct INodeType;
struct NodeTypeObj
{
    const INodeType* iNodeType;
    NodeTypeHandle nodeTypeHandle;

    bool isValid() const
    {
        return iNodeType && (nodeTypeHandle != kInvalidNodeTypeHandle);
    }
};

// ======================================================================
// Support for evaluation contexts
struct IGraphContext;
struct IBundle;
struct IAttributeData;
using GraphContextHandle = uint64_t;
static constexpr GraphContextHandle kInvalidGraphContextHandle = 0;
struct GraphContextObj
{
    const IGraphContext* iContext;
    // Convenience location for commonly used interfaces
    const IBundle* iBundle;
    const IAttributeData* iAttributeData;
    const omni::fabric::IToken* iToken;
    const omni::fabric::IPath* iPath;
    GraphContextHandle contextHandle;

    bool isValid() const
    {
        return iContext && (contextHandle != kInvalidGraphContextHandle);
    }
};

// ======================================================================
// Support for nodes
using NodeHandle = uint64_t;
static constexpr NodeHandle kInvalidNodeHandle = 0;
struct INode;
struct NodeObj
{
    const INode* iNode{ nullptr };
    NodeHandle nodeHandle{ kInvalidNodeHandle };
    NodeContextHandle nodeContextHandle{ NodeContextHandle::invalidValue() };

    bool isValid() const
    {
        return iNode && (nodeHandle != kInvalidNodeHandle);
    }
};

// ======================================================================
// Support for graphs
using GraphHandle = uint64_t;
static constexpr GraphHandle kInvalidGraphHandle = 0;
struct IGraph;
struct GraphObj
{
    IGraph* iGraph;
    GraphHandle graphHandle;

    bool isValid() const
    {
        return iGraph && (graphHandle != kInvalidGraphHandle);
    }
};

// ======================================================================
template <class NodeTypeClass>
using has_setContext = typename std::is_same<void,
    decltype(std::declval<NodeTypeClass&>().setContext(
        std::declval<const GraphContextObj&>()))>::value_type;

template <class NodeTypeClass, typename HandleType>
using has_setHandle = typename std::is_same<void,
    decltype(std::declval<NodeTypeClass&>().setHandle(
        std::declval<HandleType>()))>::value_type;

struct OptionalMethod
{
private:
    template <typename ClassToSet, typename HandleType>
    static void call_setHandle(ClassToSet& member, HandleType handle, std::true_type)
    {
        member.setHandle(handle);
    }
    template <typename ClassToSet, typename HandleType>
    static void call_setHandle(ClassToSet& member, HandleType handle, std::false_type)
    {
    }

    template <typename ClassToSet>
    static void call_setContext(ClassToSet& member, const GraphContextObj& context, std::true_type)
    {
        member.setContext(context);
    }
    template <typename ClassToSet>
    static void call_setContext(ClassToSet& member, const GraphContextObj& context, std::false_type)
    {
    }

public:
    template <typename ClassToSet, typename HandleType>
    static void setHandle(ClassToSet& member, HandleType handle)
    {
        call_setHandle(member, handle, is_detected<has_setHandle, ClassToSet, HandleType>());
    }
    template <typename ClassToSet>
    static void setContext(ClassToSet& member, const GraphContextObj& context)
    {
        call_setContext(member, context, is_detected<has_setContext, ClassToSet>());
    }
};

struct GraphInstanceID
{
    constexpr GraphInstanceID() : id(0){};
    constexpr GraphInstanceID(NameToken _token) : id(_token){};

    bool const operator==(GraphInstanceID const& other) const
    {
        return id == other.id;
    }
    bool const operator!=(GraphInstanceID const& other) const
    {
        return id != other.id;
    }
    bool const operator<(GraphInstanceID const& other) const
    {
        return id < other.id;
    }

    NameToken id;
};
static constexpr GraphInstanceID kUninitializedGraphId { 0 };
static_assert(std::is_standard_layout<GraphInstanceID>::value,
              "Struct must be standard layout as it is used in C-ABI interfaces");

/*
  _____                                _           _
 |  __ \                              | |         | |
 | |  | | ___ _ __  _ __ ___  ___ __ _| |_ ___  __| |
 | |  | |/ _ \ '_ \| '__/ _ \/ __/ _` | __/ _ \/ _` |
 | |__| |  __/ |_) | | |  __/ (_| (_| | ||  __/ (_| |
 |_____/ \___| .__/|_|  \___|\___\__,_|\__\___|\__,_|
             | |
             |_|
May go away at any time - what you should use are in the comments
*/
constexpr static HandleInt INVALID_TOKEN_VALUE = ~HandleInt(0);

} // namespace core
} // namespace graph
} // namespace omni