2019-01-09 10:55:11 +00:00
|
|
|
// Copyright(c) 2015-2019, NVIDIA CORPORATION. All rights reserved.
|
2017-12-21 11:40:48 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <iostream>
|
|
|
|
#include <set>
|
|
|
|
#include <vector>
|
|
|
|
#include <tinyxml2.h>
|
|
|
|
|
|
|
|
class VulkanHppGenerator
|
|
|
|
{
|
|
|
|
public:
|
2019-03-19 14:34:00 +00:00
|
|
|
VulkanHppGenerator();
|
2017-12-21 11:40:48 +00:00
|
|
|
|
2019-08-27 07:02:49 +00:00
|
|
|
void appendBaseTypes(std::string & str) const;
|
|
|
|
void appendBitmasks(std::string & str) const;
|
|
|
|
void appendDispatchLoaderDynamic(std::string & str); // use vkGet*ProcAddress to get function pointers
|
|
|
|
void appendDispatchLoaderStatic(std::string & str); // use exported symbols from loader
|
|
|
|
void appendDispatchLoaderDefault(std::string & str); // typedef to DispatchLoaderStatic or undefined type, based on VK_NO_PROTOTYPES
|
|
|
|
void appendEnums(std::string & str) const;
|
|
|
|
void appendForwardDeclarations(std::string & str) const;
|
|
|
|
void appendHandles(std::string & str) const;
|
|
|
|
void appendHandlesCommandDefintions(std::string & str) const;
|
|
|
|
void appendResultExceptions(std::string & str) const;
|
|
|
|
void appendStructs(std::string & str) const;
|
|
|
|
void appendStructureChainValidation(std::string & str);
|
|
|
|
void appendThrowExceptions(std::string & str) const;
|
2018-10-15 12:27:42 +00:00
|
|
|
void checkCorrectness();
|
2017-12-21 11:40:48 +00:00
|
|
|
std::string const& getTypesafeCheck() const;
|
|
|
|
std::string const& getVersion() const;
|
|
|
|
std::string const& getVulkanLicenseHeader() const;
|
|
|
|
void readCommands(tinyxml2::XMLElement const* element);
|
|
|
|
void readComment(tinyxml2::XMLElement const* element);
|
|
|
|
void readEnums(tinyxml2::XMLElement const* element);
|
|
|
|
void readExtensions(tinyxml2::XMLElement const* element);
|
|
|
|
void readFeature(tinyxml2::XMLElement const* element);
|
2018-12-03 13:33:37 +00:00
|
|
|
void readPlatforms(tinyxml2::XMLElement const* element);
|
2017-12-21 11:40:48 +00:00
|
|
|
void readTags(tinyxml2::XMLElement const* element);
|
|
|
|
void readTypes(tinyxml2::XMLElement const* element);
|
|
|
|
|
|
|
|
private:
|
2018-01-04 09:51:17 +00:00
|
|
|
struct BitmaskData
|
|
|
|
{
|
2019-01-09 10:55:11 +00:00
|
|
|
BitmaskData(std::string const& r)
|
2019-06-11 08:12:37 +00:00
|
|
|
: requirement(r)
|
2019-01-09 10:55:11 +00:00
|
|
|
{}
|
|
|
|
|
2019-06-11 08:12:37 +00:00
|
|
|
std::string requirement; // original vulkan name: VK*FlagBits
|
2019-01-09 10:55:11 +00:00
|
|
|
std::string platform;
|
|
|
|
std::string alias; // original vulkan name
|
2018-01-04 09:51:17 +00:00
|
|
|
};
|
|
|
|
|
2019-01-09 10:55:11 +00:00
|
|
|
struct TypeData
|
2017-12-21 11:40:48 +00:00
|
|
|
{
|
2019-01-09 10:55:11 +00:00
|
|
|
std::string compose() const;
|
2017-12-21 11:40:48 +00:00
|
|
|
|
2019-01-09 10:55:11 +00:00
|
|
|
bool operator==(TypeData const& rhs) const
|
|
|
|
{
|
|
|
|
return (prefix == rhs.prefix) && (type == rhs.type) && (postfix == rhs.postfix);
|
|
|
|
}
|
2017-12-21 11:40:48 +00:00
|
|
|
|
2019-01-09 10:55:11 +00:00
|
|
|
std::string prefix;
|
|
|
|
std::string type;
|
|
|
|
std::string postfix;
|
2017-12-21 11:40:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ParamData
|
|
|
|
{
|
2019-01-14 09:09:19 +00:00
|
|
|
ParamData()
|
|
|
|
: optional(false)
|
|
|
|
{}
|
|
|
|
|
2019-01-09 10:55:11 +00:00
|
|
|
TypeData type;
|
2017-12-21 11:40:48 +00:00
|
|
|
std::string name;
|
|
|
|
std::string arraySize;
|
|
|
|
std::string len;
|
|
|
|
bool optional;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CommandData
|
|
|
|
{
|
|
|
|
CommandData()
|
2019-01-09 10:55:11 +00:00
|
|
|
: isAlias(false)
|
2017-12-21 11:40:48 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
std::vector<ParamData> params;
|
2019-01-09 10:55:11 +00:00
|
|
|
std::string platform;
|
2017-12-21 11:40:48 +00:00
|
|
|
std::string returnType;
|
|
|
|
std::vector<std::string> successCodes;
|
2018-03-01 10:51:30 +00:00
|
|
|
bool isAlias;
|
2017-12-21 11:40:48 +00:00
|
|
|
};
|
|
|
|
|
2019-07-03 11:53:44 +00:00
|
|
|
struct EnumValueData
|
|
|
|
{
|
|
|
|
EnumValueData(std::string const& vulkan, std::string const& vk, bool singleBit_)
|
|
|
|
: vulkanValue(vulkan)
|
|
|
|
, vkValue(vk)
|
|
|
|
, singleBit(singleBit_)
|
|
|
|
{}
|
|
|
|
|
|
|
|
std::string vulkanValue;
|
|
|
|
std::string vkValue;
|
|
|
|
bool singleBit;
|
|
|
|
};
|
|
|
|
|
2017-12-21 11:40:48 +00:00
|
|
|
struct EnumData
|
|
|
|
{
|
2019-07-03 11:53:44 +00:00
|
|
|
void addEnumValue(std::string const& valueName, bool bitmask, bool bitpos, std::string const& prefix, std::string const& postfix, std::string const& tag);
|
2017-12-21 11:40:48 +00:00
|
|
|
|
2019-01-09 10:55:11 +00:00
|
|
|
std::vector<std::pair<std::string, std::string>> aliases; // pairs of vulkan enum value and corresponding vk::-namespace enum value
|
2019-03-20 16:39:51 +00:00
|
|
|
std::string platform;
|
2019-07-03 11:53:44 +00:00
|
|
|
std::vector<EnumValueData> values;
|
2017-12-21 11:40:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct HandleData
|
|
|
|
{
|
2019-01-09 10:55:11 +00:00
|
|
|
std::string alias;
|
|
|
|
std::map<std::string, CommandData> commands;
|
|
|
|
std::string deleteCommand;
|
|
|
|
std::string deletePool;
|
|
|
|
std::set<std::string> childrenHandles;
|
2017-12-21 11:40:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct MemberData
|
|
|
|
{
|
2019-01-09 10:55:11 +00:00
|
|
|
TypeData type;
|
2017-12-21 11:40:48 +00:00
|
|
|
std::string name;
|
|
|
|
std::string arraySize;
|
|
|
|
std::string values;
|
|
|
|
};
|
|
|
|
|
2019-01-09 10:55:11 +00:00
|
|
|
struct StructureData
|
2017-12-21 11:40:48 +00:00
|
|
|
{
|
2019-01-09 10:55:11 +00:00
|
|
|
StructureData()
|
2017-12-21 11:40:48 +00:00
|
|
|
: returnedOnly(false)
|
|
|
|
{}
|
|
|
|
|
|
|
|
bool returnedOnly;
|
|
|
|
bool isUnion;
|
|
|
|
std::vector<MemberData> members;
|
2019-04-01 07:30:06 +00:00
|
|
|
std::string platform;
|
2017-12-21 11:40:48 +00:00
|
|
|
std::vector<std::string> structExtends;
|
2019-03-18 19:48:10 +00:00
|
|
|
std::vector<std::string> aliases;
|
2018-05-07 14:44:32 +00:00
|
|
|
std::string subStruct;
|
2017-12-21 11:40:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
2019-08-27 07:02:49 +00:00
|
|
|
void appendArgumentPlainType(std::string & str, ParamData const& paramData) const;
|
|
|
|
void appendArguments(std::string & str, CommandData const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool twoStep, bool firstCall, bool singular, size_t from, size_t to) const;
|
|
|
|
void appendArgumentVector(std::string & str, size_t paramIndex, ParamData const& paramData, size_t returnParamIndex, size_t templateParamIndex, bool twoStep, bool firstCall, bool singular) const;
|
|
|
|
void appendArgumentVulkanType(std::string & str, ParamData const& paramData) const;
|
|
|
|
void appendBitmask(std::string & os, std::string const& bitmaskName, std::string const& bitmaskAlias, std::string const& enumName, std::vector<EnumValueData> const& enumValues) const;
|
|
|
|
void appendBitmaskToStringFunction(std::string & str, std::string const& flagsName, std::string const& enumName, std::vector<EnumValueData> const& enumValues) const;
|
|
|
|
void appendCall(std::string &str, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool twoStep, bool firstCall, bool singular) const;
|
|
|
|
void appendCommand(std::string & str, std::string const& indentation, std::string const& name, std::pair<std::string, CommandData> const& commandData, bool definition) const;
|
|
|
|
void appendEnum(std::string & str, std::pair<std::string, EnumData> const& enumData) const;
|
|
|
|
void appendEnumToString(std::string & str, std::pair<std::string, EnumData> const& enumData) const;
|
|
|
|
void appendFunction(std::string & str, std::string const& indentation, std::string const& name, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool twoStep, std::string const& enhancedReturnType, bool definition, bool enhanced, bool singular, bool unique, bool isStructureChain, bool withAllocator) const;
|
|
|
|
void appendFunctionBodyEnhanced(std::string & str, std::string const& indentation, std::string const& commandName, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool twoStep, std::string const& enhancedReturnType, bool singular, bool unique, bool isStructureChain, bool withAllocator) const;
|
|
|
|
std::string appendFunctionBodyEnhancedLocalReturnVariable(std::string & str, std::string const& indentation, CommandData const& commandData, size_t returnParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool twoStep, std::string const& enhancedReturnType, bool singular, bool isStructureChain, bool withAllocator) const;
|
|
|
|
void appendFunctionBodyEnhancedLocalReturnVariableVectorSize(std::string & str, std::vector<ParamData> const& params, std::pair<size_t, size_t> const& vectorParamIndex, size_t returnParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool withAllocator) const;
|
|
|
|
void appendFunctionBodyEnhancedMultiVectorSizeCheck(std::string & str, std::string const& indentation, std::string const& commandName, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, std::map<size_t, size_t> const& vectorParamIndices) const;
|
|
|
|
void appendFunctionBodyEnhancedReturnResultValue(std::string & str, std::string const& indentation, std::string const& returnName, std::string const& commandName, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, bool twoStep, bool singular, bool unique) const;
|
|
|
|
void appendFunctionBodyEnhancedSingleStep(std::string & str, std::string const& indentation, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool singular) const;
|
|
|
|
void appendFunctionBodyEnhancedTwoStep(std::string & str, std::string const& indentation, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool singular, std::string const& returnName) const;
|
|
|
|
void appendFunctionBodyEnhancedVectorOfUniqueHandles(std::string & str, std::string const& indentation, std::string const& commandName, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool twoStep, bool singular, bool withAllocator) const;
|
|
|
|
void appendFunctionBodyStandard(std::string & str, std::string const& indentation, std::pair<std::string, CommandData> const& commandData) const;
|
|
|
|
void appendFunctionBodyStandardArgument(std::string & str, TypeData const& typeData, std::string const& name) const;
|
|
|
|
bool appendFunctionHeaderArgumentEnhanced(std::string & str, ParamData const& param, size_t paramIndex, std::map<size_t, size_t> const& vectorParamIndices, bool skip, bool argEncountered, bool isTemplateParam, bool isLastArgument, bool singular, bool withDefaults, bool withAllocator) const;
|
|
|
|
void appendFunctionHeaderArgumentEnhancedPointer(std::string & str, ParamData const& param, std::string const& strippedParameterName, bool withDefaults, bool withAllocator) const;
|
|
|
|
void appendFunctionHeaderArgumentEnhancedSimple(std::string & str, ParamData const& param, bool lastArgument, bool withDefaults, bool withAllocator) const;
|
|
|
|
void appendFunctionHeaderArgumentEnhancedVector(std::string & str, ParamData const& param, std::string const& strippedParameterName, bool hasSizeParam, bool isTemplateParam, bool singular, bool withDefaults, bool withAllocator) const;
|
|
|
|
void appendFunctionHeaderArguments(std::string & str, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool enhanced, bool singular, bool withDefaults, bool withAllocator) const;
|
|
|
|
void appendFunctionHeaderArgumentsEnhanced(std::string & str, std::pair<std::string, CommandData> const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool singular, bool withDefaults, bool withAllocator) const;
|
|
|
|
void appendFunctionHeaderArgumentsStandard(std::string & str, std::pair<std::string, CommandData> const& commandData, bool withDefaults) const;
|
|
|
|
bool appendFunctionHeaderArgumentStandard(std::string & str, ParamData const& param, bool argEncountered, bool isLastArgument, bool withDefaults) const;
|
|
|
|
void appendFunctionHeaderReturnType(std::string & str, CommandData const& commandData, size_t returnParamIndex, std::map<size_t, size_t> const& vectorParamIndices, std::string const& enhancedReturnType, bool enhanced, bool singular, bool unique, bool isStructureChain) const;
|
|
|
|
void appendFunctionHeaderTemplate(std::string & str, std::string const& indentation, size_t returnParamIndex, size_t templateParamIndex, std::string const& enhancedReturnType, bool enhanced, bool singular, bool unique, bool withDefault, bool isStructureChain) const;
|
|
|
|
void appendHandle(std::string & str, std::pair<std::string, HandleData> const& handle, std::set<std::string> & listedHandles) const;
|
|
|
|
void appendPlatformEnter(std::string & str, std::string const& platform) const;
|
|
|
|
void appendPlatformLeave(std::string & str, std::string const& platform) const;
|
|
|
|
void appendStruct(std::string & str, std::pair<std::string, StructureData> const& structure, std::set<std::string> & listedStructures) const;
|
|
|
|
void appendStructCompareOperators(std::string & str, std::pair<std::string, StructureData> const& structure) const;
|
|
|
|
std::string appendStructConstructor(std::pair<std::string, StructureData> const& structData, std::string const& prefix, bool withLayoutStructure) const;
|
|
|
|
bool appendStructConstructorArgument(std::string & str, bool listedArgument, std::string const& indentation, MemberData const& memberData) const;
|
|
|
|
void appendStructCopyConstructors(std::string & str, std::string const& vkName, bool withLayoutStructure) const;
|
|
|
|
void appendStructMembers(std::string & str, StructureData const& structData, std::string const& prefix) const;
|
|
|
|
void appendStructSetter(std::string & str, std::string const& structureName, MemberData const& memberData) const;
|
|
|
|
void appendStructure(std::string & str, std::pair<std::string, StructureData> const& structure) const;
|
|
|
|
void appendUnion(std::string & str, std::pair<std::string, StructureData> const& structure) const;
|
|
|
|
void appendUniqueTypes(std::string &str, std::string const& parentType, std::set<std::string> const& childrenTypes) const;
|
2019-01-09 10:55:11 +00:00
|
|
|
bool containsUnion(std::string const& type) const;
|
|
|
|
std::string defaultValue(std::string const& type) const;
|
|
|
|
std::string determineEnhancedReturnType(CommandData const& commandData, size_t returnParamIndex, std::map<size_t, size_t> const& vectorParamIndices, bool twoStep, bool isStructureChain) const;
|
|
|
|
size_t determineReturnParamIndex(CommandData const& commandData, std::map<size_t, size_t> const& vectorParamIndices, bool twoStep) const;
|
|
|
|
std::string determineSubStruct(std::pair<std::string, StructureData> const& structure) const;
|
|
|
|
size_t determineTemplateParamIndex(std::vector<ParamData> const& params, std::map<size_t, size_t> const& vectorParamIndices) const;
|
|
|
|
std::map<size_t, size_t> determineVectorParamIndices(std::vector<ParamData> const& params) const;
|
|
|
|
bool isTwoStepAlgorithm(std::vector<ParamData> const& params) const;
|
|
|
|
void linkCommandToHandle(std::string const& name, CommandData const& commandData);
|
|
|
|
void readBaseType(tinyxml2::XMLElement const* element, std::map<std::string, std::string> const& attributes);
|
|
|
|
void readBitmask(tinyxml2::XMLElement const* element, std::map<std::string, std::string> const& attributes);
|
|
|
|
void readBitmaskAlias(int lineNum, std::string const& alias, std::map<std::string, std::string> const& attributes, std::vector<tinyxml2::XMLElement const*> const& children);
|
|
|
|
void readCommand(tinyxml2::XMLElement const* element);
|
|
|
|
void readCommandAlias(int lineNum, std::string const& alias, std::map<std::string, std::string> const& attributes, std::vector<tinyxml2::XMLElement const*> const& children);
|
|
|
|
ParamData readCommandParam(tinyxml2::XMLElement const* element);
|
|
|
|
std::string readCommandProto(tinyxml2::XMLElement const* element, std::string & returnType);
|
|
|
|
std::vector<std::string> readCommandSuccessCodes(std::map<std::string, std::string> const& attributes);
|
|
|
|
void readDefine(tinyxml2::XMLElement const* element, std::map<std::string, std::string> const& attributes);
|
|
|
|
void readEnum(tinyxml2::XMLElement const* element, EnumData & enumData, bool bitmask, std::string const& prefix, std::string const& postfix);
|
|
|
|
void readExtension(tinyxml2::XMLElement const* element);
|
|
|
|
void readExtensionDisabled(std::vector<tinyxml2::XMLElement const*> const& children);
|
|
|
|
void readExtensionDisabledRequire(tinyxml2::XMLElement const* element);
|
|
|
|
void readExtensionRequire(tinyxml2::XMLElement const* element, std::string const& platform, std::string const& tag);
|
|
|
|
void readExtensionRequireCommand(tinyxml2::XMLElement const* element, std::string const& platform);
|
|
|
|
void readExtensionRequireType(tinyxml2::XMLElement const* element, std::string const& platform);
|
2017-12-21 11:40:48 +00:00
|
|
|
void readFeatureRequire(tinyxml2::XMLElement const* element);
|
2019-01-09 10:55:11 +00:00
|
|
|
void readFuncpointer(tinyxml2::XMLElement const* element, std::map<std::string, std::string> const& attributes);
|
|
|
|
void readHandle(tinyxml2::XMLElement const* element, std::map<std::string, std::string> const& attributes);
|
2018-12-03 13:33:37 +00:00
|
|
|
void readPlatform(tinyxml2::XMLElement const* element);
|
2019-03-18 19:48:10 +00:00
|
|
|
void readRequireEnum(tinyxml2::XMLElement const* element, std::string const& tag);
|
2019-01-09 10:55:11 +00:00
|
|
|
void readStruct(tinyxml2::XMLElement const* element, bool isUnion, std::map<std::string, std::string> const& attributes);
|
|
|
|
void readStructAlias(int lineNum, std::string const& name, std::string const& alias, std::map<std::string, std::string> const& attributes);
|
|
|
|
MemberData readStructMember(tinyxml2::XMLElement const* element);
|
|
|
|
std::vector<MemberData> readStructMembers(std::vector<tinyxml2::XMLElement const*> const& children);
|
2017-12-21 11:40:48 +00:00
|
|
|
void readTag(tinyxml2::XMLElement const* element);
|
|
|
|
void readType(tinyxml2::XMLElement const* element);
|
2019-01-09 10:55:11 +00:00
|
|
|
void registerDeleter(std::string const& name, std::pair<std::string, CommandData> const& commandData);
|
|
|
|
void unlinkCommandFromHandle(std::string const& name);
|
2019-03-19 14:34:00 +00:00
|
|
|
#if !defined(NDEBUG)
|
|
|
|
void readRequires(tinyxml2::XMLElement const* element, std::map<std::string, std::string> const& attributes);
|
|
|
|
#endif
|
2017-12-21 11:40:48 +00:00
|
|
|
|
|
|
|
private:
|
2019-01-09 10:55:11 +00:00
|
|
|
std::map<std::string, std::string> m_baseTypes;
|
|
|
|
std::map<std::string, EnumData> m_bitmaskBits;
|
|
|
|
std::map<std::string, BitmaskData> m_bitmasks;
|
|
|
|
std::map<std::string, std::string> m_commandToHandle;
|
|
|
|
std::map<std::string, EnumData> m_enums;
|
|
|
|
std::set<std::string> m_extendedStructs; // structs which are referenced by the structextends tag
|
|
|
|
std::map<std::string, HandleData> m_handles;
|
|
|
|
std::map<std::string, std::string> m_platforms;
|
|
|
|
std::map<std::string, std::string> m_structureAliases;
|
|
|
|
std::map<std::string, StructureData> m_structures;
|
|
|
|
std::set<std::string> m_tags;
|
|
|
|
std::string m_typesafeCheck;
|
|
|
|
std::string m_version;
|
|
|
|
std::string m_vulkanLicenseHeader;
|
2017-12-21 11:40:48 +00:00
|
|
|
#if !defined(NDEBUG)
|
2019-03-19 14:34:00 +00:00
|
|
|
std::set<std::string> m_defaultZeroTypes;
|
2019-01-09 10:55:11 +00:00
|
|
|
std::set<std::string> m_defines; // just used for verfication in readExtensionType
|
2017-12-21 11:40:48 +00:00
|
|
|
#endif
|
2019-01-09 10:55:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const size_t INVALID_INDEX = (size_t)~0;
|