diff --git a/Include/auROXTL/auContainerUtils.hpp b/Include/auROXTL/auContainerUtils.hpp index f9326f7..d384ab8 100644 --- a/Include/auROXTL/auContainerUtils.hpp +++ b/Include/auROXTL/auContainerUtils.hpp @@ -134,15 +134,41 @@ inline bool AuExists(const Range &a, const Key &key) template && !AuIsPointer_v)> inline bool AuExists(const Map &map, const Key &key) { - auto itr = map.find(key); - if (itr != map.end()) + if constexpr (AuIsSame_v && + Aurora::Build::kCurrentLanguage != Aurora::Build::ELanguage::eCpp20 && + (int)Aurora::Build::kCurrentLanguage < 20) { - return true; + for (auto itr = map.begin(); + itr != map.end(); + ) + { + if constexpr (AuIsHashMap_v || AuIsBST_v) + { + if (itr->first == key) + { + return true; + } + } + else + { + if (*itr == key) + { + return true; + } + } + + itr++; + } } else { - return false; + auto itr = map.find(key); + if (itr != map.end()) + { + return true; + } } + return false; } template @@ -161,31 +187,89 @@ inline bool AuTryClear(Container &container) template && !AuIsPointer_v)> inline bool AuTryRemove(Range &list, const Key &key) { - auto itr = std::find(list.begin(), list.end(), key); - if (itr != list.end()) + if constexpr (AuIsSame_v && + Aurora::Build::kCurrentLanguage != Aurora::Build::ELanguage::eCpp20 && + (int)Aurora::Build::kCurrentLanguage < 20) { - list.erase(itr); - return true; + for (auto itr = list.begin(); + itr != list.end(); + ) + { + if constexpr (AuIsHashMap_v || AuIsBST_v) + { + if (itr->first == key) + { + list.erase(itr); + return true; + } + } + else + { + if (*itr == key) + { + list.erase(itr); + return true; + } + } + + itr++; + } } else { - return false; + auto itr = std::find(list.begin(), list.end(), key); + if (itr != list.end()) + { + list.erase(itr); + return true; + } } + + return false; } template && !AuIsPointer_v)> inline bool AuTryRemove(Map &map, const Key &key) { - auto itr = map.find(key); - if (itr != map.end()) + if constexpr (AuIsSame_v && + Aurora::Build::kCurrentLanguage != Aurora::Build::ELanguage::eCpp20 && + (int)Aurora::Build::kCurrentLanguage < 20) { - map.erase(itr); - return true; + for (auto itr = map.begin(); + itr != map.end(); + ) + { + if constexpr (AuIsHashMap_v || AuIsBST_v) + { + if (itr->first == key) + { + map.erase(itr); + return true; + } + } + else + { + if (*itr == key) + { + map.erase(itr); + return true; + } + } + + itr++; + } } else { - return false; + auto itr = map.find(key); + if (itr != map.end()) + { + map.erase(itr); + return true; + } } + + return false; } template diff --git a/Include/auROXTL/auHashUtils.hpp b/Include/auROXTL/auHashUtils.hpp index f99ce8f..b51f5e9 100644 --- a/Include/auROXTL/auHashUtils.hpp +++ b/Include/auROXTL/auHashUtils.hpp @@ -245,6 +245,17 @@ namespace AuHash return lhs == rhs; } }; + + template <> + struct equal + { + using is_transparent = void; + + bool operator()(std::string_view lhs, std::string_view rhs) const + { + return lhs == rhs; + } + }; } template )> @@ -286,6 +297,71 @@ namespace AuHash return uHashCode; } }; + + // container bug in msvc? +#if 0 + template <> + struct hash + { + size_t operator()(std::string_view txt) const + { + return AuFnv1aRuntime(txt.data(), txt.size()); + } + }; +#endif + + template <> + struct hash + { + using is_transparent = void; + using transparent_key_equal = equal; + + size_t operator()(std::string_view txt) const + { + return hash{}(txt); + } + }; + + template <> + struct less + { + using is_transparent = void; + + bool operator()(std::string_view lhs, std::string_view rhs) const + { + #if 0 + return AuFnv1aRuntime(lhs.data(), lhs.size()) < AuFnv1aRuntime(rhs.data(), rhs.size()); + #else + return hash{}(lhs) < hash{}(rhs); + #endif + } + }; + + template <> + struct less + { + bool operator()(std::string_view lhs, std::string_view rhs) const + { + #if 0 + return AuFnv1aRuntime(lhs.data(), lhs.size()) < AuFnv1aRuntime(rhs.data(), rhs.size()); + #else + return hash{}(lhs) < hash{}(rhs); + #endif + } + }; + + template <> + struct less + { + bool operator()(const char *lhs, const char *rhs) const + { + #if 0 + return AuFnv1aRuntime(lhs, strlen(lhs)) < AuFnv1aRuntime(rhs, strlen(rhs)); + #else + return hash{}(lhs) < hash{}(rhs); + #endif + } + }; } template diff --git a/Include/auROXTL/auStringUtils.hpp b/Include/auROXTL/auStringUtils.hpp index 0cdafbd..7a9cbb3 100644 --- a/Include/auROXTL/auStringUtils.hpp +++ b/Include/auROXTL/auStringUtils.hpp @@ -10,18 +10,18 @@ ***/ #pragma once -static auline bool AuStringContains(const AuString &value, const AuString &subpattern) +static auline bool AuStringContains(const AuROString &value, const AuROString &subpattern) { - return value.find(subpattern) != AuString::npos; + return value.find(subpattern) != AuROString::npos; } -static auline bool AuEndsWith(AuString const &value, AuString const &ending) +static auline bool AuEndsWith(AuROString const &value, AuROString const &ending) { if (ending.size() > value.size()) return false; return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); } -static auline bool AuStartsWith(AuString const &value, AuString const &starting) +static auline bool AuStartsWith(AuROString const &value, AuROString const &starting) { #if defined(AU_STRING_IS_TINYUTF_EXPERIMENT) return value.starts_with(starting); @@ -30,67 +30,436 @@ static auline bool AuStartsWith(AuString const &value, AuString const &starting) #endif } -#if defined(AU_STRING_IS_TINYUTF_EXPERIMENT) - -static AuString AuStringTransform(const AuString &in, const AuSupplierConsumer &out) -{ - AuString cpy = in; - for (int i = 0; i < cpy.length(); i++) - { - cpy[i] = out(cpy[i]); - } - return cpy; -} - -static auline AuString AuToUpper(const AuString &in) -{ - return AuStringTransform(in, std::toupper); -} - - -static auline AuString AuToLower(const AuString &in) -{ - return AuStringTransform(in, std::toupper); -} - -#else - template -static auline AuString AuToStringASCIIOp(T op, const AuString &in) +static auline AuString AuCodepointsTransformASCIIOp(T op, const AuROString &in) { AuString ret; - ret.resize(in.size()); - std::transform(in.begin(), in.end(), ret.begin(), [=](const char &c) + auto uLength = in.length(); + + ret.resize(uLength); + + const char *pItr = in.data(); + const char *pEnd = pItr + uLength; + + AuUInt32 uCounter {}; + while (pItr != pEnd) { - return op(c); - }); + AuUInt32 nby {}; + auto ch = *pItr; + unsigned int result = (ch & 0xF0); + + if ((ch & 0x80) == 0) + { + nby = 1; + } + else if ((ch & 0xE0) == 0xC0) + { + nby = 2; + } + else if (result == 0xE0) + { + nby = 3; + } + else if (result == 0xF0) + { + if ((ch & 0x08) == 0x08) + { + nby = 5; + } + else if ((ch & 0x0c) == 0x0c) + { + nby = 6; + } + else + { + nby = 4; + } + } + else + { + break; + } + + if (pItr + nby > pEnd) + { + break; + } + + if (nby == 1) + { + ret[uCounter] = op(in[uCounter]); + } + else + { + AuMemcpy(&ret[uCounter], &in[uCounter], nby); + } + + uCounter += nby; + pItr += nby; + } + return ret; } -static auline AuString AuToLower(const AuString &in) +static auline AuUInt AuCodepointsCount(const AuROString &in) { - return AuToStringASCIIOp(std::tolower, in); -} + AuUInt uCounter {}; + auto uLength = in.length(); -static auline AuString AuToUpper(const AuString &in) -{ - return AuToStringASCIIOp(std::toupper, in); -} -#endif + const char *pItr = in.data(); + const char *pEnd = pItr + uLength; -static auline AuString &AuReplaceAll(AuString &str, const AuString &from, const AuString &to) -{ - size_t start_pos = 0; - while ((start_pos = str.find(from, start_pos)) != std::string::npos) + while (pItr != pEnd) { - str.replace(start_pos, from.length(), to); - start_pos += to.length(); // Handles case where 'to' is a substring of 'from' + AuUInt32 nby {}; + auto ch = *pItr; + unsigned int result = (ch & 0xF0); + + if ((ch & 0x80) == 0) + { + nby = 1; + } + else if ((ch & 0xE0) == 0xC0) + { + nby = 2; + } + else if (result == 0xE0) + { + nby = 3; + } + else if (result == 0xF0) + { + if ((ch & 0x08) == 0x08) + { + nby = 5; + } + else if ((ch & 0x0c) == 0x0c) + { + // Special/Historic UTF8 + nby = 6; + } + else + { + nby = 4; + } + } + else + { + break; + } + + if (pItr + nby > pEnd) + { + break; + } + + uCounter++; + pItr += nby; + } + + return uCounter; +} + +static auline AuUInt AuCodepointsNextLength(const AuROString &in) +{ + if (in.length()) + { + auto ch = in[0]; + unsigned int result = (ch & 0xF0); + + if ((ch & 0x80) == 0) + { + return 1; + } + else if ((ch & 0xE0) == 0xC0) + { + return 2; + } + else if (result == 0xE0) + { + return 3; + } + else if (result == 0xF0) + { + if ((ch & 0x08) == 0x08) + { + return 5; + } + else if ((ch & 0x0c) == 0x0c) + { + // Special/Historic UTF8 + return 6; + } + else + { + return 4; + } + } + } + + return 0; +} + +static auline char AuToLower(char c) +{ + return c ? c | 0x20 : 0; +} + +static auline char AuToUpper(char c) +{ + return c & ~0x20; +} + +static auline AuString AuCodepointsToLower(const AuROString &in) +{ + return AuCodepointsTransformASCIIOp(((char(*)(char))&AuToLower), in); +} + +static auline AuString AuCodepointsToUpper(const AuROString &in) +{ + return AuCodepointsTransformASCIIOp(((char(*)(char))&AuToUpper), in); +} + +static auline AuString AuToLower(const AuROString &in) +{ + return AuCodepointsToLower(in); +} + +static auline AuString AuToUpper(const AuROString &in) +{ + return AuCodepointsToUpper(in); +} + +static AuList AuCodepointsDecode(const AuROString &in) +{ + AuList ret; + + if (in.empty()) + { + return ret; + } + + auto uLength = in.length(); + + ret.reserve(uLength); + + const char *pItr = in.data(); + const char *pEnd = pItr + uLength; + + while (pItr < pEnd) + { + AuUInt32 c {}; + + if ((c = *pItr) <= 0x7FU) + { + ++pItr; + } + else + { + AuUInt32 nby {}; + + if ((*pItr & 0xC0U) != 0xC0U) + { + return {}; + } + + for (AuUInt8 b = *pItr; (b & 0x80U) != 0; b <<= 1, ++nby) + { + } + + if (nby > 6) + { + return {}; + } + + if (AuUInt(pEnd - pItr) < AuUInt(nby)) + { + return {}; + } + + c = *pItr & (AuUInt8(0xFFU) >> (nby + 1)); + + for (AuUInt32 i = 1; i < nby; ++i) + { + if ((pItr[i] & 0xC0U) != 0x80U) + { + return {}; + } + + c = (c << 6) | (pItr[i] & 0x3FU); + } + + pItr += nby; + } + + ret.push_back(c); + } + + return ret; +} + +static void AuCodepointsEncodeInto(AuUInt32 uCodepoint, AuString &out) +{ + if (uCodepoint < 0x80) + { + auto uLength = out.size(); + out.resize(uLength + 1); + out[uLength] = static_cast(uCodepoint); + } + else if (uCodepoint < 0x800) + { + auto uLength = out.size(); + out.resize(uLength + 2); + out[uLength] = static_cast((uCodepoint >> 6) | 0xc0); + out[uLength + 1] = static_cast((uCodepoint & 0x3f) | 0x80); + } + else if (uCodepoint < 0x10000) + { + auto uLength = out.size(); + out.resize(uLength + 3); + out[uLength] = static_cast((uCodepoint >> 12) | 0xe0); + out[uLength + 1] = static_cast(((uCodepoint >> 6) & 0x3f) | 0x80); + out[uLength + 2] = static_cast((uCodepoint & 0x3f) | 0x80); + } + else if (uCodepoint < 0x200000) + { + auto uLength = out.size(); + out.resize(uLength + 4); + out[uLength] = static_cast((uCodepoint >> 18) | 0xf0); + out[uLength + 1] = static_cast(((uCodepoint >> 12) & 0x3f) | 0x80); + out[uLength + 2] = static_cast(((uCodepoint >> 6) & 0x3f) | 0x80); + out[uLength + 3] = static_cast((uCodepoint & 0x3f) | 0x80); + } + else if (uCodepoint < 0x4000000) + { + auto uLength = out.size(); + out.resize(uLength + 5); + out[uLength] = static_cast((uCodepoint >> 24) | 0xf8); + out[uLength + 1] = static_cast(((uCodepoint >> 18) & 0x3f) | 0x80); + out[uLength + 2] = static_cast(((uCodepoint >> 12) & 0x3f) | 0x80); + out[uLength + 3] = static_cast(((uCodepoint >> 6) & 0x3f) | 0x80); + out[uLength + 4] = static_cast((uCodepoint & 0x3f) | 0x80); + } + else if (uCodepoint < 0x80000000) + { + auto uLength = out.size(); + out.resize(uLength + 6); + out[uLength] = static_cast((uCodepoint >> 30) | 0xfc); + out[uLength + 1] = static_cast(((uCodepoint >> 24) & 0x3f) | 0x80); + out[uLength + 2] = static_cast(((uCodepoint >> 18) & 0x3f) | 0x80); + out[uLength + 3] = static_cast(((uCodepoint >> 12) & 0x3f) | 0x80); + out[uLength + 4] = static_cast(((uCodepoint >> 6) & 0x3f) | 0x80); + out[uLength + 5] = static_cast((uCodepoint & 0x3f) | 0x80); + } +} + +template +static AuString AuCodepointsTransform(T op, const AuROString &in) +{ + AuString ret; + + if (in.empty()) + { + return ret; + } + + auto uLength = in.length(); + + ret.reserve(uLength); + + const char *pItr = in.data(); + const char *pEnd = pItr + uLength; + + while (pItr < pEnd) + { + AuUInt32 c {}; + + if ((c = *pItr) <= 0x7FU) + { + ++pItr; + } + else + { + AuUInt32 nby {}; + + if ((*pItr & 0xC0U) != 0xC0U) + { + return {}; + } + + for (AuUInt8 b = *pItr; (b & 0x80U) != 0; b <<= 1, ++nby) + { + } + + if (nby > 6) + { + return {}; + } + + if (AuUInt(pEnd - pItr) < AuUInt(nby)) + { + return {}; + } + + c = *pItr & (AuUInt8(0xFFU) >> (nby + 1)); + + for (AuUInt32 i = 1; i < nby; ++i) + { + if ((pItr[i] & 0xC0U) != 0x80U) + { + return {}; + } + + c = (c << 6) | (pItr[i] & 0x3FU); + } + + pItr += nby; + } + + c = op(c); + + AuCodepointsEncodeInto(c, ret); + } + + return ret; +} + +static AuString &AuReplaceAll(AuString &str, const AuROString &from, const AuROString &to) +{ + AuUInt uStartPosition {}; + while ((uStartPosition = str.find(from, uStartPosition)) != AuROString::npos) + { + str.replace(uStartPosition, from.length(), to); + uStartPosition += to.length(); } return str; } // i told myself not to copy this, required a split function twice, now here we are :D -static auline AuList AuSplitString(const AuString &str, const AuString &delim, bool ignoreEmpty = true) +static AuList AuSplitString(const AuROString &str, const AuROString &delim, bool ignoreEmpty = true) +{ + AuList tokens; + AuUInt prev = 0, pos = 0; + tokens.reserve(str.size() / 16); + do + { + pos = str.find(delim, prev); + if (pos == AuROString::npos) + { + pos = str.length(); + } + auto token = str.substr(prev, pos - prev); + if ((!token.empty()) && ignoreEmpty) + { + tokens.push_back(token); + } + prev = pos + delim.length(); + } + while (pos < str.length() && prev < str.length()); + return tokens; +} + +static AuList AuSplitStringLegacy(const AuROString &str, const AuROString &delim, bool ignoreEmpty = true) { AuList tokens; AuUInt prev = 0, pos = 0; @@ -98,9 +467,15 @@ static auline AuList AuSplitString(const AuString &str, const AuString do { pos = str.find(delim, prev); - if (pos == AuString::npos) pos = str.length(); + if (pos == AuROString::npos) + { + pos = str.length(); + } auto token = str.substr(prev, pos - prev); - if ((!token.empty()) && ignoreEmpty) tokens.push_back(token); + if ((!token.empty()) && ignoreEmpty) + { + tokens.push_back(AuString(token)); + } prev = pos + delim.length(); } while (pos < str.length() && prev < str.length()); diff --git a/Include/auROXTL/auUTF8StringView.hpp b/Include/auROXTL/auUTF8StringView.hpp index 543ef4e..7d0c33f 100644 --- a/Include/auROXTL/auUTF8StringView.hpp +++ b/Include/auROXTL/auUTF8StringView.hpp @@ -2,6 +2,7 @@ // TODO: -using AuUTF8StringView = std::string_view; +using AuROString = std::string_view; +using AuUTF8StringView = AuROString; using AuU8View = AuUTF8StringView; \ No newline at end of file