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