omni/extras/PathMap.h
File members: omni/extras/PathMap.h
// Copyright (c) 2021-2022, 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 "../core/Platform.h"
#include "../../carb/extras/Utf8Parser.h"
#include "../../carb/CarbWindows.h"
#include <map>
#include <unordered_map>
#if !OMNI_PLATFORM_WINDOWS
# include <algorithm>
#endif
namespace omni
{
namespace extras
{
#if OMNI_PLATFORM_WINDOWS
struct PathHash
{
size_t accumulateHash(size_t value, const void* data, size_t bytes) const noexcept
{
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
for (size_t i = 0; i < bytes; i++)
{
value ^= ptr[i];
value *= std::_FNV_prime;
}
return value;
}
size_t operator()(const std::string& key) const noexcept
{
carb::extras::Utf8Iterator it(key.c_str());
carb::extras::Utf8Iterator::CodePoint cp;
size_t hash = std::_FNV_offset_basis;
size_t count;
int result;
while (it)
{
cp = *it;
it++;
count = carb::extras::Utf8Parser::encodeUtf16CodePoint(cp, &cp);
result = LCMapStringW(CARBWIN_LOCALE_INVARIANT, CARBWIN_LCMAP_LOWERCASE, reinterpret_cast<WCHAR*>(&cp),
(int)count, reinterpret_cast<WCHAR*>(&cp), 2);
if (result != 0)
hash = accumulateHash(hash, &cp, count * sizeof(WCHAR));
}
return hash;
}
};
struct PathCompare
{
int32_t operator()(const std::string& left, const std::string& right) const noexcept
{
carb::extras::Utf8Iterator itLeft(left.c_str());
carb::extras::Utf8Iterator itRight(right.c_str());
carb::extras::Utf8Iterator::CodePoint l;
carb::extras::Utf8Iterator::CodePoint r;
size_t countLeft;
size_t countRight;
int resultLeft;
int resultRight;
// walk the strings and compare the lower case versions of each codepoint.
while (itLeft && itRight)
{
l = *itLeft;
r = *itRight;
itLeft++;
itRight++;
countLeft = carb::extras::Utf8Parser::encodeUtf16CodePoint(l, &l);
countRight = carb::extras::Utf8Parser::encodeUtf16CodePoint(r, &r);
resultLeft = LCMapStringW(CARBWIN_LOCALE_INVARIANT, CARBWIN_LCMAP_LOWERCASE, reinterpret_cast<WCHAR*>(&l),
(int)countLeft, reinterpret_cast<WCHAR*>(&l), 2);
resultRight = LCMapStringW(CARBWIN_LOCALE_INVARIANT, CARBWIN_LCMAP_LOWERCASE, reinterpret_cast<WCHAR*>(&r),
(int)countRight, reinterpret_cast<WCHAR*>(&r), 2);
if (l != r)
return l - r;
}
// the strings only match if both ended at the same point and all codepoints matched.
if (!itLeft && !itRight)
return 0;
if (!itLeft)
return -1;
return 1;
}
};
struct PathGreater
{
bool operator()(const std::string& left, const std::string& right) const noexcept
{
PathCompare compare;
return compare(left, right) > 0;
}
};
struct PathLess
{
bool operator()(const std::string& left, const std::string& right) const noexcept
{
PathCompare compare;
return compare(left, right) < 0;
}
};
struct PathEqual
{
bool operator()(const std::string& left, const std::string& right) const noexcept
{
// the two strings are different lengths -> they cannot possibly match => fail.
if (left.length() != right.length())
return false;
PathCompare compare;
return compare(left, right) == 0;
}
};
#else
using PathHash = std::hash<std::string>;
using PathGreater = std::greater<std::string>;
using PathLess = std::less<std::string>;
using PathEqual = std::equal_to<std::string>;
#endif
template <typename T, class Compare = PathLess>
using PathMap = std::map<std::string, T, Compare>;
template <typename T, class Hash = PathHash, class KeyEqual = PathEqual>
using UnorderedPathMap = std::unordered_map<std::string, T, Hash, KeyEqual>;
} // namespace extras
} // namespace omni