#pragma once #include #include #include #include #include "../common/compat.hpp" #include "../if/if.hpp" #ifndef SPRAWL_CHR_MAX #define SPRAWL_CHR_MAX 64 #endif static_assert(SPRAWL_CHR_MAX >= 2 && (SPRAWL_CHR_MAX & (SPRAWL_CHR_MAX - 1)) == 0 && SPRAWL_CHR_MAX <= 32768, "SPRAWL_CHR_MAX must be a power of 2 between 2 and 32768"); #define SPRAWL_CHR(str, size, idx) (idx < size ? str[idx] : '\0') #define SPRAWL_CHR_2(str, size, idx) SPRAWL_CHR(str, size, idx), SPRAWL_CHR(str, size, idx+1) #if SPRAWL_CHR_MAX >= 4 #define SPRAWL_CHR_4(str, size, idx) SPRAWL_CHR_2(str, size, idx), SPRAWL_CHR_2(str, size, idx+2) #endif #if SPRAWL_CHR_MAX >= 8 #define SPRAWL_CHR_8(str, size, idx) SPRAWL_CHR_4(str, size, idx), SPRAWL_CHR_4(str, size, idx+4) #endif #if SPRAWL_CHR_MAX >= 16 #define SPRAWL_CHR_16(str, size, idx) SPRAWL_CHR_8(str, size, idx), SPRAWL_CHR_8(str, size, idx+8) #endif #if SPRAWL_CHR_MAX >= 32 #define SPRAWL_CHR_32(str, size, idx) SPRAWL_CHR_16(str, size, idx), SPRAWL_CHR_16(str, size, idx+16) #endif #if SPRAWL_CHR_MAX >= 64 #define SPRAWL_CHR_64(str, size, idx) SPRAWL_CHR_32(str, size, idx), SPRAWL_CHR_32(str, size, idx+32) #endif #if SPRAWL_CHR_MAX >= 128 #define SPRAWL_CHR_128(str, size, idx) SPRAWL_CHR_64(str, size, idx), SPRAWL_CHR_64(str, size, idx+64) #endif #if SPRAWL_CHR_MAX >= 256 #define SPRAWL_CHR_256(str, size, idx) SPRAWL_CHR_128(str, size, idx), SPRAWL_CHR_128(str, size, idx+128) #endif #if SPRAWL_CHR_MAX >= 512 #define SPRAWL_CHR_512(str, size, idx) SPRAWL_CHR_256(str, size, idx), SPRAWL_CHR_256(str, size, idx+256) #endif #if SPRAWL_CHR_MAX >= 1024 #define SPRAWL_CHR_1024(str, size, idx) SPRAWL_CHR_512(str, size, idx), SPRAWL_CHR_512(str, size, idx+512) #endif #if SPRAWL_CHR_MAX >= 2048 #define SPRAWL_CHR_2048(str, size, idx) SPRAWL_CHR_1024(str, size, idx), SPRAWL_CHR_1024(str, size, idx+1024) #endif #if SPRAWL_CHR_MAX >= 4096 #define SPRAWL_CHR_4096(str, size, idx) SPRAWL_CHR_2048(str, size, idx), SPRAWL_CHR_2048(str, size, idx+2048) #endif #if SPRAWL_CHR_MAX >= 8192 #define SPRAWL_CHR_8192(str, size, idx) SPRAWL_CHR_4096(str, size, idx), SPRAWL_CHR_4096(str, size, idx+4096) #endif #if SPRAWL_CHR_MAX >= 16384 #define SPRAWL_CHR_16384(str, size, idx) SPRAWL_CHR_8192(str, size, idx), SPRAWL_CHR_8192(str, size, idx+8192) #endif #if SPRAWL_CHR_MAX >= 32768 #define SPRAWL_CHR_32768(str, size, idx) SPRAWL_CHR_16384(str, size, idx), SPRAWL_CHR_16384(str, size, idx+16384) #endif #define SPRAWL_CHR_MACRO_2(val) SPRAWL_CHR_ ## val #define SPRAWL_CHR_MACRO(val) SPRAWL_CHR_MACRO_2(val) #define SPRAWL_CHR_MAX_MACRO SPRAWL_CHR_MACRO(SPRAWL_CHR_MAX) #define SPRAWL_TAG(s) ::sprawl::detail::TagWrapper< ::sprawl::detail::SizeChecker::value, 1, ::sprawl::Tag<0>, ::sprawl::detail::IsPositive::value, true, SPRAWL_CHR_MAX_MACRO(s, sizeof(s), 0)>::type #include "detail/tag_detail.hpp" #include "type_list.hpp" namespace sprawl { //MSVC likes to complain about integer constant overflow here, but hash algorithms use that intentionally so this is being unilaterally disabled for this section. #if SPRAWL_COMPILER_MSVC # pragma warning(push) # pragma warning(disable: 4307) #endif #if SPRAWL_64_BIT template struct Murmur3 { template struct Hash { static constexpr size_t outputHash1 = detail::murmur3::Murmur3::value; static constexpr size_t outputHash2 = outputHash1 ^ sizeof...(t_Chars); static constexpr size_t outputHash3 = outputHash2 ^ (outputHash2 >> 33); static constexpr size_t outputHash4 = outputHash3 * 0xff51afd7ed558ccdULL; static constexpr size_t outputHash5 = outputHash4 ^ (outputHash4 >> 33); static constexpr size_t outputHash6 = outputHash5 * 0xc4ceb9fe1a85ec53ULL; static constexpr size_t value = outputHash6 ^ (outputHash6 >> 33); }; }; #else template struct Murmur3 { template struct Hash { static constexpr size_t outputHash1 = detail::murmur3::Murmur3::value; static constexpr size_t outputHash2 = outputHash1 ^ sizeof...(t_Chars); static constexpr size_t outputHash3 = outputHash2 ^ (outputHash2 >> 16); static constexpr size_t outputHash4 = outputHash3 * 0x85ebca6b; static constexpr size_t outputHash5 = outputHash4 ^ (outputHash4 >> 13); static constexpr size_t outputHash6 = outputHash5 * 0xc2b2ae35; static constexpr size_t value = outputHash6 ^ (outputHash6 >> 16); }; }; #endif #if SPRAWL_COMPILER_MSVC # pragma warning(pop) #endif template struct CharIn { template using Check = detail::CharIn; }; struct IsWhitespace { template struct Check { static constexpr bool value = detail::CharIn::value; }; }; struct IsLineEnding { template struct Check { static constexpr bool value = detail::CharIn::value; }; }; struct IsDigit { template struct Check { static constexpr bool value = detail::CharIn::value; }; }; struct IsUpper { template struct Check { static constexpr bool value = ('A' <= t_CheckChar && t_CheckChar <= 'Z'); }; }; struct IsLower { template struct Check { static constexpr bool value = ('a' <= t_CheckChar && t_CheckChar <= 'z'); }; }; struct IsAlpha { template struct Check { static constexpr bool value = IsUpper::Check::value || IsLower::Check::value; }; }; struct IsAlnum { template struct Check { static constexpr bool value = IsAlpha::Check::value || IsDigit::Check::value; }; }; struct IsPrintable { template struct Check { static constexpr bool value = (32 <= t_CheckChar && t_CheckChar <= 127) || t_CheckChar < 0; }; }; struct IsTitle { template struct ComplexCheck { static constexpr bool value = IsUpper::Check::value ? (IsWhitespace::Check::value || t_PreviousChar == -1) : !(IsWhitespace::Check::value || t_PreviousChar == -1); }; }; template struct Upper { static constexpr char value = (('a' <= t_CurrentChar && t_CurrentChar <= 'z') ? ((t_CurrentChar - 'a') + 'A') : t_CurrentChar); }; template struct Lower { static constexpr char value = (('A' <= t_CurrentChar && t_CurrentChar <= 'Z') ? ((t_CurrentChar - 'A') + 'a') : t_CurrentChar); }; template struct SwapCase { static constexpr char value = (('A' <= t_CurrentChar && t_CurrentChar <= 'Z') ? ((t_CurrentChar - 'A') + 'a') : ('a' <= t_CurrentChar && t_CurrentChar <= 'z') ? ((t_CurrentChar - 'a') + 'A') : t_CurrentChar); }; template struct Title { static constexpr char value = t_PreviousChar == -1 || IsWhitespace::Check::value ? Upper::value : Lower::value; }; template struct Capitalize { static constexpr char value = t_PreviousChar == -1 ? Upper::value : Lower::value; }; template struct Tag { public: static constexpr ssize_t length = t_Len; static CONSTEXPR_ARRAY char name[t_Len + 1] SPRAWL_CONSTEXPR_INCLASS_INIT({ t_Chars..., '\0' }); typedef ssize_t length_type; typedef char char_type; constexpr Tag(){} template using Substring = typename detail::TagWrapper<(t_Idx < 0 ? 0 : (t_Length >(t_Len - t_Idx)) ? (t_Len - t_Idx) : t_Length), t_Idx < 0 ? 0 : (1 - t_Idx), Tag<0>, detail::IsPositive(t_Len - t_Idx)) ? (t_Len - t_Idx) : t_Length)>::value, detail::IsPositive::value, t_Chars...>::type; template static constexpr ssize_t Find() { return detail::FindTag, t_OtherTagType, 0>::result != -1 ? detail::FindTag, t_OtherTagType, 0>::result + t_Start : -1; } template static constexpr ssize_t Find(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len) { return t_Length - 1 <= Tag::length && t_Length - 1 <= (end - start) ? find_(0, start, end, str, t_Chars...) : -1; } template static constexpr ssize_t RFind() { return detail::RFindTag, t_OtherTagType, 0>::result != -1 ? detail::RFindTag, t_OtherTagType, 0>::result + t_Start : -1; } template static constexpr ssize_t RFind(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len) { return t_Length - 1 <= Tag::length && t_Length - 1 <= (end - start) ? rfind_(0, start, end, str, t_Chars...) : -1; } template static constexpr ssize_t FindFirstOf() { return detail::FindPred, t_PredType, 0>::result != -1 ? detail::FindPred, t_PredType, 0>::result + t_Start : -1; } template static constexpr ssize_t FindFirstOf(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len) { return findFirstOf_(0, start, end, str, t_Chars...); } template static constexpr ssize_t FindLastOf() { return detail::RFindPred, t_PredType, 0>::result != -1 ? detail::RFindPred, t_PredType, 0>::result + t_Start : -1; } template static constexpr ssize_t FindLastOf(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len) { return findLastOf_(0, start, end, str, t_Chars...); } template static constexpr ssize_t FindFirstNotOf() { return detail::FindNotPred, t_PredType, 0>::result != -1 ? detail::FindNotPred, t_PredType, 0>::result + t_Start : -1; } template static constexpr ssize_t FindFirstNotOf(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len) { return findFirstNotOf_(0, start, end, str, t_Chars...); } template static constexpr ssize_t FindLastNotOf() { return detail::RFindNotPred, t_PredType, 0>::result != -1 ? detail::RFindNotPred, t_PredType, 0>::result + t_Start : -1; } template static constexpr ssize_t FindLastNotOf(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len) { return findLastNotOf_(0, start, end, str, t_Chars...); } template