tag.hpp #1

  • //
  • guest/
  • ShadauxCat/
  • Sprawl/
  • Mainline/
  • tag/
  • tag.hpp
  • View
  • Commits
  • Open Download .zip Download (52 KB)
#pragma once

#include <type_traits>
#include <stddef.h>
#include <sys/types.h>
#include <stdint.h>

#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<sizeof(s) - 1>::value, 1, ::sprawl::Tag<0>, ::sprawl::detail::IsPositive<sizeof(s) - 1>::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<size_t t_Seed>
	struct Murmur3
	{
		template<char... t_Chars>
		struct Hash
		{
			static constexpr size_t outputHash1 = detail::murmur3::Murmur3<t_Seed, t_Chars...>::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<size_t t_Seed>
	struct Murmur3
	{
		template<char... t_Chars>
		struct Hash
		{
			static constexpr size_t outputHash1 = detail::murmur3::Murmur3<t_Seed, t_Chars...>::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<char... t_Chars>
	struct CharIn
	{
		template<char t_CheckChar>
		using Check = detail::CharIn<t_CheckChar, t_Chars...>;
	};

	struct IsWhitespace
	{
		template<char t_CheckChar>
		struct Check
		{
			static constexpr bool value = detail::CharIn<t_CheckChar, ' ', '\n', '\t', '\v', '\f', '\r'>::value;
		};
	};

	struct IsLineEnding
	{
		template<char t_CheckChar>
		struct Check
		{
			static constexpr bool value = detail::CharIn<t_CheckChar, '\n', '\r'>::value;
		};
	};

	struct IsDigit
	{
		template<char t_CheckChar>
		struct Check
		{
			static constexpr bool value = detail::CharIn<t_CheckChar, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'>::value;
		};
	};

	struct IsUpper
	{
		template<char t_CheckChar>
		struct Check
		{
			static constexpr bool value = ('A' <= t_CheckChar && t_CheckChar <= 'Z');
		};
	};

	struct IsLower
	{
		template<char t_CheckChar>
		struct Check
		{
			static constexpr bool value = ('a' <= t_CheckChar && t_CheckChar <= 'z');
		};
	};

	struct IsAlpha
	{
		template<char t_CheckChar>
		struct Check
		{
			static constexpr bool value = IsUpper::Check<t_CheckChar>::value || IsLower::Check<t_CheckChar>::value;
		};
	};

	struct IsAlnum
	{
		template<char t_CheckChar>
		struct Check
		{
			static constexpr bool value = IsAlpha::Check<t_CheckChar>::value || IsDigit::Check<t_CheckChar>::value;
		};
	};

	struct IsPrintable
	{
		template<char t_CheckChar>
		struct Check
		{
			static constexpr bool value = (32 <= t_CheckChar && t_CheckChar <= 127) || t_CheckChar < 0;
		};
	};

	struct IsTitle
	{
		template<char t_PreviousChar, char t_CheckChar>
		struct ComplexCheck
		{
			static constexpr bool value = IsUpper::Check<t_CheckChar>::value ? (IsWhitespace::Check<t_PreviousChar>::value || t_PreviousChar == -1) : !(IsWhitespace::Check<t_PreviousChar>::value || t_PreviousChar == -1);
		};
	};

	template<char t_PreviousChar, char t_CurrentChar>
	struct Upper
	{
		static constexpr char value = (('a' <= t_CurrentChar && t_CurrentChar <= 'z') ? ((t_CurrentChar - 'a') + 'A') : t_CurrentChar);
	};

	template<char t_PreviousChar, char t_CurrentChar>
	struct Lower
	{
		static constexpr char value = (('A' <= t_CurrentChar && t_CurrentChar <= 'Z') ? ((t_CurrentChar - 'A') + 'a') : t_CurrentChar);
	};

	template<char t_PreviousChar, char t_CurrentChar>
	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<char t_PreviousChar, char t_CurrentChar>
	struct Title
	{
		static constexpr char value = t_PreviousChar == -1 || IsWhitespace::Check<t_PreviousChar>::value ? Upper<t_PreviousChar, t_CurrentChar>::value : Lower<t_PreviousChar, t_CurrentChar>::value;
	};

	template<char t_PreviousChar, char t_CurrentChar>
	struct Capitalize
	{
		static constexpr char value = t_PreviousChar == -1 ? Upper<t_PreviousChar, t_CurrentChar>::value : Lower<t_PreviousChar, t_CurrentChar>::value;
	};

	template<ssize_t t_Len, char... t_Chars>
	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;

		template<ssize_t t_Idx, ssize_t t_Length = t_Len - t_Idx>
		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_Idx < 0 ? 0 : ((t_Length >(t_Len - t_Idx)) ? (t_Len - t_Idx) : t_Length)>::value, detail::IsPositive<t_Idx < 0 ? 0 : (1 - t_Idx)>::value, t_Chars...>::type;

		template<typename t_OtherTagType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t Find()
		{
			return detail::FindTag<Substring<t_Start, t_End - t_Start>, t_OtherTagType, 0>::result != -1 ? detail::FindTag<Substring<t_Start, t_End - t_Start>, t_OtherTagType, 0>::result + t_Start : -1;
		}


		template<ssize_t t_Length>
		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<typename t_OtherTagType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t RFind()
		{
			return detail::RFindTag<Substring<t_Start, t_End - t_Start>, t_OtherTagType, 0>::result != -1 ? detail::RFindTag<Substring<t_Start, t_End - t_Start>, t_OtherTagType, 0>::result + t_Start : -1;
		}

		template<ssize_t t_Length>
		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<typename t_PredType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t FindFirstOf()
		{
			return detail::FindPred<Substring<t_Start, t_End - t_Start>, t_PredType, 0>::result != -1 ? detail::FindPred<Substring<t_Start, t_End - t_Start>, t_PredType, 0>::result + t_Start : -1;
		}

		template<ssize_t t_Length>
		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<typename t_PredType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t FindLastOf()
		{
			return detail::RFindPred<Substring<t_Start, t_End - t_Start>, t_PredType, 0>::result != -1 ? detail::RFindPred<Substring<t_Start, t_End - t_Start>, t_PredType, 0>::result + t_Start : -1;
		}

		template<ssize_t t_Length>
		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<typename t_PredType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t FindFirstNotOf()
		{
			return detail::FindNotPred<Substring<t_Start, t_End - t_Start>, t_PredType, 0>::result != -1 ? detail::FindNotPred<Substring<t_Start, t_End - t_Start>, t_PredType, 0>::result + t_Start : -1;
		}

		template<ssize_t t_Length>
		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<typename t_PredType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t FindLastNotOf()
		{
			return detail::RFindNotPred<Substring<t_Start, t_End - t_Start>, t_PredType, 0>::result != -1 ? detail::RFindNotPred<Substring<t_Start, t_End - t_Start>, t_PredType, 0>::result + t_Start : -1;
		}

		template<ssize_t t_Length>
		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<template <char t_PreviousChar, char t_CurrentChar> class t_TransformType>
		using Transform = typename detail::TransformTag<t_TransformType, Tag<0>, -1, t_Chars...>::type;

		//Using as a namespace so following namespace naming conventions despite being a struct.
		struct tag_detail
		{
			template<typename t_OtherTagType>
			struct AppendTagHelper
			{

			};

			template<ssize_t t_OtherLength, char... t_OtherChars>
			struct AppendTagHelper<Tag<t_OtherLength, t_OtherChars...>>
			{
				typedef Tag<t_Len + t_OtherLength, t_Chars..., t_OtherChars...> type;
			};

#if SPRAWL_COMPILER_MSVC
			template<ssize_t t_TargetIdx, bool t_CharWithinBounds, char... t_AdditionalChars>
			struct CharAt;

			template<ssize_t t_TargetIdx, bool t_CharWithinBounds, char t_FirstChar, char... t_AdditionalChars>
			struct CharAt<t_TargetIdx, t_CharWithinBounds, t_FirstChar, t_AdditionalChars...>
			{
				static constexpr char value = t_TargetIdx < 0 ? -1 :
					t_TargetIdx == 0 ? t_FirstChar :
					CharAt<t_TargetIdx - 1, t_CharWithinBounds, t_AdditionalChars...>::value;
			};

			template<ssize_t t_TargetIdx, bool t_CharWithinBounds, char t_FirstChar>
			struct CharAt<t_TargetIdx, t_CharWithinBounds, t_FirstChar>
			{
				static constexpr char value = t_TargetIdx < 0 ? -1 : t_TargetIdx == 0 ? t_FirstChar : -1;
			};

			template<ssize_t t_TargetIdx, bool t_CharWithinBounds>
			struct CharAt<t_TargetIdx, t_CharWithinBounds>
			{
				static constexpr char value = -1;
			};

			template<char t_NextChar, bool t_CharWithinBounds>
			struct CharAt<-1, t_CharWithinBounds, t_NextChar>
			{
				static constexpr char value = -1;
			};
#else
			template<ssize_t t_TargetIdx, bool t_CharWithinBounds, char... t_Chars>
			struct CharAt
			{
				static constexpr char value = name[t_TargetIdx];
			};

			template<ssize_t t_TargetIdx, char... t_Chars>
			struct CharAt<t_TargetIdx, false, t_Chars...>
			{
				static constexpr char value = -1;
			};
#endif

			template<typename t_PredicateType, ssize_t t_Idx = 0, bool t_ShouldStrip = t_PredicateType::template Check<CharAt<t_Idx, t_Idx >= 0 && t_Idx <= t_Len, t_Chars...>::value>::value>
			struct LStripHelper
			{
				typedef typename LStripHelper<t_PredicateType, t_Idx + 1>::type type;
			};

			template<typename t_PredicateType, ssize_t t_Idx>
			struct LStripHelper<t_PredicateType, t_Idx, false>
			{
				typedef Substring<t_Idx> type;
			};

			template<typename t_PredicateType, ssize_t t_Idx = 0, bool t_ShouldStrip = t_PredicateType::template Check<CharAt<t_Len - t_Idx - 1, (t_Len - t_Idx - 1) >= 0 && (t_Len - t_Idx - 1) <= t_Len, t_Chars...>::value>::value>
			struct RStripHelper
			{
				typedef typename RStripHelper<t_PredicateType, t_Idx + 1>::type type;
			};

			template<typename t_PredicateType, ssize_t t_Idx>
			struct RStripHelper<t_PredicateType, t_Idx, false>
			{
				typedef Substring<0, t_Len - t_Idx> type;
			};

			template<typename t_SearchStringType, ssize_t t_SplitLocation>
			struct PartitionHelper
			{
				typedef TypeList<Substring<0, t_SplitLocation>, t_SearchStringType, Substring<t_SplitLocation + t_SearchStringType::length>> type;
			};
			template<typename t_SearchStringType>
			struct PartitionHelper<t_SearchStringType, -1>
			{
				typedef TypeList<Tag, SPRAWL_TAG(""), SPRAWL_TAG("")> type;
			};

			template<typename t_TagToSearchType, typename t_SearchStringType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct SplitHelper
			{
				typedef typename SplitHelper<
					typename t_TagToSearchType::template Substring<t_SplitLocation + t_SearchStringType::length>,
					t_SearchStringType,
					typename t_TypeSoFar::template Append<
					typename t_TagToSearchType::template Substring<0, t_SplitLocation>
					>,
					t_TagToSearchType::template Substring<t_SplitLocation + t_SearchStringType::length>::template Find<t_SearchStringType>(),
					t_CurrentSplit + 1,
					t_MaxSplit
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_SearchStringType, typename t_TypeSoFar, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct SplitHelper<t_TagToSearchType, t_SearchStringType, t_TypeSoFar, -1, t_CurrentSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_SearchStringType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_MaxSplit>
			struct SplitHelper<t_TagToSearchType, t_SearchStringType, t_TypeSoFar, t_SplitLocation, t_MaxSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_SearchStringType, typename t_TypeSoFar, ssize_t t_MaxSplit>
			struct SplitHelper<t_TagToSearchType, t_SearchStringType, t_TypeSoFar, -1, t_MaxSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_AccessibleByGetType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct SplitHelperInList
			{
				typedef typename SplitHelperInList<
					typename t_TagToSearchType::template Substring<
					t_SplitLocation + detail::MatchLength<
					t_TagToSearchType, t_SplitLocation, t_AccessibleByGetType, 0, detail::HasGet<t_AccessibleByGetType, 1>
					>::value
					>,
					t_AccessibleByGetType,
					typename t_TypeSoFar::template Append<
					typename t_TagToSearchType::template Substring<0, t_SplitLocation>
					>,
					t_TagToSearchType::template Substring<
					t_SplitLocation + detail::MatchLength<
					t_TagToSearchType, t_SplitLocation, t_AccessibleByGetType, 0, detail::HasGet<t_AccessibleByGetType, 1>
					>::value
					>::template FindFirstInList<t_AccessibleByGetType>(),
					t_CurrentSplit + 1,
					t_MaxSplit
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_AccessibleByGetType, typename t_TypeSoFar, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct SplitHelperInList<t_TagToSearchType, t_AccessibleByGetType, t_TypeSoFar, -1, t_CurrentSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_AccessibleByGetType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_MaxSplit>
			struct SplitHelperInList<t_TagToSearchType, t_AccessibleByGetType, t_TypeSoFar, t_SplitLocation, t_MaxSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_AccessibleByGetType, typename t_TypeSoFar, ssize_t t_MaxSplit>
			struct SplitHelperInList<t_TagToSearchType, t_AccessibleByGetType, t_TypeSoFar, -1, t_MaxSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};


			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct SplitHelperAnyOf
			{
				typedef typename SplitHelperAnyOf<
					typename t_TagToSearchType::template Substring<t_SplitLocation + 1>,
					t_PredType,
					typename t_TypeSoFar::template Append<
					typename t_TagToSearchType::template Substring<0, t_SplitLocation>
					>,
					t_TagToSearchType::template Substring<t_SplitLocation + 1>::template FindFirstOf<t_PredType>(),
					t_CurrentSplit + 1,
					t_MaxSplit
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct SplitHelperAnyOf<t_TagToSearchType, t_PredType, t_TypeSoFar, -1, t_CurrentSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_MaxSplit>
			struct SplitHelperAnyOf<t_TagToSearchType, t_PredType, t_TypeSoFar, t_SplitLocation, t_MaxSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_MaxSplit>
			struct SplitHelperAnyOf<t_TagToSearchType, t_PredType, t_TypeSoFar, -1, t_MaxSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct SplitHelperAnyNotOf
			{
				typedef typename SplitHelperAnyNotOf<
					typename t_TagToSearchType::template Substring<t_SplitLocation + 1>,
					t_PredType,
					typename t_TypeSoFar::template Append<
					typename t_TagToSearchType::template Substring<0, t_SplitLocation>
					>,
					t_TagToSearchType::template Substring<t_SplitLocation + 1>::template FindFirstNotOf<t_PredType>(),
					t_CurrentSplit + 1,
					t_MaxSplit
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct SplitHelperAnyNotOf<t_TagToSearchType, t_PredType, t_TypeSoFar, -1, t_CurrentSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_MaxSplit>
			struct SplitHelperAnyNotOf<t_TagToSearchType, t_PredType, t_TypeSoFar, t_SplitLocation, t_MaxSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_MaxSplit>
			struct SplitHelperAnyNotOf<t_TagToSearchType, t_PredType, t_TypeSoFar, -1, t_MaxSplit, t_MaxSplit>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};


			template<typename t_TagToSearchType, typename t_SearchStringType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct RSplitHelper
			{
				typedef typename RSplitHelper<
					typename t_TagToSearchType::template Substring<0, t_SplitLocation>,
					t_SearchStringType,
					typename TypeList<typename t_TagToSearchType::template Substring<t_SplitLocation + t_SearchStringType::length>>::template Extend<t_TypeSoFar>,
					t_TagToSearchType::template Substring<0, t_SplitLocation>::template RFind<t_SearchStringType>(),
					t_CurrentSplit + 1,
					t_MaxSplit
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_SearchStringType, typename t_TypeSoFar, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct RSplitHelper<t_TagToSearchType, t_SearchStringType, t_TypeSoFar, -1, t_CurrentSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};

			template<typename t_TagToSearchType, typename t_SearchStringType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_MaxSplit>
			struct RSplitHelper<t_TagToSearchType, t_SearchStringType, t_TypeSoFar, t_SplitLocation, t_MaxSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};

			template<typename t_TagToSearchType, typename t_SearchStringType, typename t_TypeSoFar, ssize_t t_MaxSplit>
			struct RSplitHelper<t_TagToSearchType, t_SearchStringType, t_TypeSoFar, -1, t_MaxSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};


			template<typename t_TagToSearchType, typename t_AccessibleByGetType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct RSplitHelperInList
			{
				typedef typename RSplitHelperInList<
					typename t_TagToSearchType::template Substring<0, t_SplitLocation>,
					t_AccessibleByGetType,
					typename TypeList<typename t_TagToSearchType::template Substring<t_SplitLocation + detail::MatchLength<t_TagToSearchType, t_SplitLocation, t_AccessibleByGetType, 0, detail::HasGet<t_AccessibleByGetType, 1>>::value>>::template Extend<t_TypeSoFar>,
					t_TagToSearchType::template Substring<0, t_SplitLocation>::template FindLastInList<t_AccessibleByGetType>(),
					t_CurrentSplit + 1,
					t_MaxSplit
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_AccessibleByGetType, typename t_TypeSoFar, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct RSplitHelperInList<t_TagToSearchType, t_AccessibleByGetType, t_TypeSoFar, -1, t_CurrentSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};

			template<typename t_TagToSearchType, typename t_AccessibleByGetType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_MaxSplit>
			struct RSplitHelperInList<t_TagToSearchType, t_AccessibleByGetType, t_TypeSoFar, t_SplitLocation, t_MaxSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};

			template<typename t_TagToSearchType, typename t_AccessibleByGetType, typename t_TypeSoFar, ssize_t t_MaxSplit>
			struct RSplitHelperInList<t_TagToSearchType, t_AccessibleByGetType, t_TypeSoFar, -1, t_MaxSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};


			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct RSplitHelperAnyOf
			{
				typedef typename RSplitHelperAnyOf<
					typename t_TagToSearchType::template Substring<0, t_SplitLocation>,
					t_PredType,
					typename TypeList<typename t_TagToSearchType::template Substring<t_SplitLocation + 1>>::template Extend<t_TypeSoFar>,
					t_TagToSearchType::template Substring<0, t_SplitLocation>::template FindLastOf<t_PredType>(),
					t_CurrentSplit + 1,
					t_MaxSplit
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct RSplitHelperAnyOf<t_TagToSearchType, t_PredType, t_TypeSoFar, -1, t_CurrentSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_MaxSplit>
			struct RSplitHelperAnyOf<t_TagToSearchType, t_PredType, t_TypeSoFar, t_SplitLocation, t_MaxSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_MaxSplit>
			struct RSplitHelperAnyOf<t_TagToSearchType, t_PredType, t_TypeSoFar, -1, t_MaxSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};


			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct RSplitHelperAnyNotOf
			{
				typedef typename RSplitHelperAnyNotOf<
					typename t_TagToSearchType::template Substring<0, t_SplitLocation>,
					t_PredType,
					typename TypeList<typename t_TagToSearchType::template Substring<t_SplitLocation + 1>>::template Extend<t_TypeSoFar>,
					t_TagToSearchType::template Substring<0, t_SplitLocation>::template FindLastNotOf<t_PredType>(),
					t_CurrentSplit + 1,
					t_MaxSplit
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_CurrentSplit, ssize_t t_MaxSplit>
			struct RSplitHelperAnyNotOf<t_TagToSearchType, t_PredType, t_TypeSoFar, -1, t_CurrentSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_MaxSplit>
			struct RSplitHelperAnyNotOf<t_TagToSearchType, t_PredType, t_TypeSoFar, t_SplitLocation, t_MaxSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};

			template<typename t_TagToSearchType, typename t_PredType, typename t_TypeSoFar, ssize_t t_MaxSplit>
			struct RSplitHelperAnyNotOf<t_TagToSearchType, t_PredType, t_TypeSoFar, -1, t_MaxSplit, t_MaxSplit>
			{
				typedef typename TypeList<t_TagToSearchType>::template Extend<t_TypeSoFar> type;
			};



			template<typename t_TagToSearchType, typename t_TypeSoFar, ssize_t t_SplitLocation, ssize_t t_EndOfSplit, bool t_KeepEnds>
			struct SplitLinesHelper
			{
				typedef typename SplitLinesHelper<
					typename t_TagToSearchType::template Substring<t_EndOfSplit + 1>,
					typename t_TypeSoFar::template Append<
					typename t_TagToSearchType::template Substring<0, t_KeepEnds ? t_EndOfSplit + 1 : t_SplitLocation>
					>,
					t_TagToSearchType::template Substring<t_EndOfSplit + 1>::template FindFirstOf<sprawl::IsLineEnding>(),
					t_TagToSearchType::template Substring<t_EndOfSplit + 1>
					::template Substring<t_TagToSearchType::template Substring<t_EndOfSplit + 1>::template FindFirstOf<sprawl::IsLineEnding>()>
					::template FindFirstNotOf<sprawl::IsLineEnding>(),
					t_KeepEnds
				>::type type;
			};

			template<typename t_TagToSearchType, typename t_TypeSoFar, ssize_t t_SplitLocation, bool t_KeepEnds>
			struct SplitLinesHelper<t_TagToSearchType, t_TypeSoFar, t_SplitLocation, -1, t_KeepEnds>
			{
				typedef typename t_TypeSoFar::template Append<typename t_TagToSearchType::template Substring<0, t_KeepEnds ? t_TagToSearchType::length : t_SplitLocation>> type;
			};

			template<typename t_TagToSearchType, typename t_TypeSoFar, bool t_KeepEnds>
			struct SplitLinesHelper<t_TagToSearchType, t_TypeSoFar, -1, -1, t_KeepEnds>
			{
				typedef typename t_TypeSoFar::template Append<t_TagToSearchType> type;
			};

			template<typename t_Type, bool integer, bool floating, bool boolean>
			struct As;

			template<typename t_Type>
			struct As<t_Type, true, false, false>
			{
				static constexpr t_Type value = t_Type(detail::TagToInt<t_Chars...>::value);
			};

			template<typename t_Type>
			struct As<t_Type, true, false, true>
			{
				static constexpr bool value = detail::TagToBool<Tag::Transform<sprawl::Lower>>::value;
			};

			template<typename t_Type>
			struct As<t_Type, false, true, false>
			{
				static constexpr t_Type value = t_Type(detail::TagToDouble<t_Chars...>::value);
			};
		};

		template<typename t_PredicateType = IsWhitespace>
		using LStrip = typename tag_detail::template LStripHelper<t_PredicateType>::type;

		template<typename t_PredicateType = IsWhitespace>
		using RStrip = typename tag_detail::template RStripHelper<t_PredicateType>::type;

		template<typename t_PredicateType = IsWhitespace>
		using Strip = typename LStrip<t_PredicateType>::template RStrip<t_PredicateType>;

		template<char t_CharToAdd>
		using AppendChar = Tag<t_Len + 1, t_Chars..., t_CharToAdd>;

		template<typename t_OtherTagType>
		using Append = typename tag_detail::template AppendTagHelper<t_OtherTagType>::type;

		template<ssize_t t_Start, ssize_t t_Length = t_Len - t_Start>
		using Erase = typename Substring<0, t_Start>::template Append<Substring<t_Start + t_Length, t_Len - (t_Start + t_Length)>>;

		template<typename t_AccessibleByGetType>
		using Join = typename detail::JoinTags<Tag, t_AccessibleByGetType, 0, detail::HasGet<t_AccessibleByGetType, 1>>::type;

		template<typename t_AccessibleByGetType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t FindFirstInList()
		{
			return detail::FindTagInList<Substring<t_Start, t_End - t_Start>, t_AccessibleByGetType, 0, detail::HasGet<t_AccessibleByGetType, 1>>::value;
		}

		template<typename t_AccessibleByGetType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t FindLastInList()
		{
			return detail::RFindTagInList<Substring<t_Start, t_End - t_Start>, t_AccessibleByGetType, 0, detail::HasGet<t_AccessibleByGetType, 1>>::value;
		}

		static constexpr bool IsAlnum()
		{
			return detail::MeetsCondition<sprawl::IsAlnum, t_Chars...>::value;
		}

		static constexpr bool IsAlpha()
		{
			return detail::MeetsCondition<sprawl::IsAlpha, t_Chars...>::value;
		}

		static constexpr bool IsDigit()
		{
			return detail::MeetsCondition<sprawl::IsDigit, t_Chars...>::value;
		}

		static constexpr bool IsLower()
		{
			return detail::MeetsCondition<sprawl::IsLower, t_Chars...>::value;
		}

		static constexpr bool IsSpace()
		{
			return detail::MeetsCondition<sprawl::IsWhitespace, t_Chars...>::value;
		}

		static constexpr bool IsUpper()
		{
			return detail::MeetsCondition<sprawl::IsUpper, t_Chars...>::value;
		}

		static constexpr bool IsPrintable()
		{
			return detail::MeetsCondition<sprawl::IsPrintable, t_Chars...>::value;
		}

		static constexpr bool IsTitle()
		{
			return detail::MeetsComplexCondition<sprawl::IsTitle, -1, t_Chars...>::value;
		}

		template<typename t_OtherTagType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr bool StartsWith()
		{
			return t_OtherTagType::length <= length && t_OtherTagType::length <= (t_End - t_Start) && Substring<t_Start, t_End - t_Start>::template Substring<0, t_OtherTagType::length>::template EqualTo<t_OtherTagType>();
		}

		template<typename t_OtherTagType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr bool EndsWith()
		{
			return t_OtherTagType::length <= length && t_OtherTagType::length <= (t_End - t_Start) && Substring<t_Start, t_End - t_Start>::template Substring<Substring<t_Start, t_End - t_Start>::length - t_OtherTagType::length, t_OtherTagType::length>::template EqualTo<t_OtherTagType>();
		}

		template<size_t t_Length>
		static constexpr bool StartsWith(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len)
		{
			(void)(str);
			(void)(start);
			(void)(end);
			return t_Length - 1 <= Tag::length && t_Length - 1 <= (end - start) && equalTo_(0, t_Length - 1, start, str, t_Chars...);
		}

		template<ssize_t t_Length>
		static constexpr bool EndsWith(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len)
		{
			(void)(str);
			(void)(start);
			(void)(end);
			return t_Length - 1 <= Tag::length && t_Length - 1 <= (end - start) && equalTo_(0, t_Length - 1, end - (t_Length - 1), str, t_Chars...);
		}

		template<typename t_OtherTagType>
		static constexpr bool Contains()
		{
			return detail::FindTag<Tag, t_OtherTagType, 0>::result != -1;
		}

		template<size_t t_Length>
		static constexpr bool Contains(char const (&str)[t_Length])
		{
			return Find(str) != -1;
		}

		template<typename t_OtherTagType, ssize_t t_Start = 0, ssize_t t_End = t_Len>
		static constexpr ssize_t Count()
		{
			return detail::CountTag<Tag, t_OtherTagType, t_Start, t_End>::value;
		}

		template<size_t t_Length>
		static constexpr ssize_t Count(char const (&str)[t_Length], ssize_t start = 0, ssize_t end = t_Len)
		{
			return Find(str, start, end) != -1 ? 1 + Count(str, Find(str, start, end) + 1, end) : 0;
		}

		template<ssize_t t_Idx>
		static constexpr char CharAt()
		{
			return tag_detail::template CharAt<t_Idx, t_Idx >= 0 && t_Idx <= t_Len, t_Chars...>::value;
		}

		template<typename t_Type>
		static constexpr t_Type As()
		{
			return tag_detail::template As<t_Type, std::is_integral<t_Type>::value, std::is_floating_point<t_Type>::value, std::is_same<t_Type, bool>::value>::value;
		}

		template<typename t_FindTagType, typename t_ReplaceWithType, ssize_t count = -1>
		using Replace = typename detail::ReplaceTags<Tag, t_FindTagType, t_ReplaceWithType, count>::type;

		template<typename t_FindTagType, typename t_ReplaceWithType, ssize_t count = -1>
		using RReplace = typename detail::RReplaceTags<Tag, t_FindTagType, t_ReplaceWithType, count>::type;

		template<typename t_TagListType, typename t_ReplaceWithType, ssize_t count = -1>
		using ReplaceAnyInList = typename detail::ReplaceTagsInList<Tag, t_TagListType, t_ReplaceWithType, count>::type;

		template<typename t_TagListType, typename t_ReplaceWithType, ssize_t count = -1>
		using RReplaceAnyInList = typename detail::RReplaceTagsInList<Tag, t_TagListType, t_ReplaceWithType, count>::type;

		template<typename t_PredType, typename t_ReplaceWithType, ssize_t count = -1>
		using ReplaceAnyOf = typename detail::ReplaceTagsAnyOf<Tag, t_PredType, t_ReplaceWithType, count, FindFirstOf<t_PredType>()>::type;

		template<typename t_PredType, typename t_ReplaceWithType, ssize_t count = -1>
		using ReplaceAnyNotOf = typename detail::ReplaceTagsAnyNotOf<Tag, t_PredType, t_ReplaceWithType, count, FindFirstNotOf<t_PredType>()>::type;

		template<typename t_PredType, typename t_ReplaceWithType, ssize_t count = -1>
		using RReplaceAnyOf = typename detail::RReplaceTagsAnyOf<Tag, t_PredType, t_ReplaceWithType, count, FindLastOf<t_PredType>()>::type;

		template<typename t_PredType, typename t_ReplaceWithType, ssize_t count = -1>
		using RReplaceAnyNotOf = typename detail::RReplaceTagsAnyNotOf<Tag, t_PredType, t_ReplaceWithType, count, FindLastNotOf<t_PredType>()>::type;

		template<ssize_t t_Start, ssize_t t_Length, typename t_OtherTagType>
		using ReplaceAt = typename Substring<0, t_Start>::template Append<t_OtherTagType>::template Append<Substring<t_Start + t_Length>>;

		template<typename t_TagToSplitOnType>
		using Partition = typename tag_detail::template PartitionHelper<t_TagToSplitOnType, Find<t_TagToSplitOnType>()>::type;

		template<typename t_TagToSplitOnType>
		using RPartition = typename tag_detail::template PartitionHelper<t_TagToSplitOnType, RFind<t_TagToSplitOnType>()>::type;

		template<typename t_TagToSplitOnType, ssize_t t_MaxSplit = -1>
		using Split = typename tag_detail::template SplitHelper<Tag, t_TagToSplitOnType, TypeList<>, Find<t_TagToSplitOnType>(), 0, t_MaxSplit>::type;

		template<typename t_AccessibleByGetType, ssize_t t_MaxSplit = -1>
		using SplitAnyInList = typename tag_detail::template SplitHelperInList<Tag, t_AccessibleByGetType, TypeList<>, FindFirstInList<t_AccessibleByGetType>(), 0, t_MaxSplit>::type;

		template<typename t_PredType, ssize_t t_MaxSplit = -1>
		using SplitAnyOf = typename tag_detail::template SplitHelperAnyOf<Tag, t_PredType, TypeList<>, FindFirstOf<t_PredType>(), 0, t_MaxSplit>::type;

		template<typename t_PredType, ssize_t t_MaxSplit = -1>
		using SplitAnyNotOf = typename tag_detail::template SplitHelperAnyNotOf<Tag, t_PredType, TypeList<>, FindFirstNotOf<t_PredType>(), 0, t_MaxSplit>::type;

		template<typename t_TagToSplitOnType, ssize_t t_MaxSplit = -1>
		using RSplit = typename tag_detail::template RSplitHelper<Tag, t_TagToSplitOnType, TypeList<>, RFind<t_TagToSplitOnType>(), 0, t_MaxSplit>::type;

		template<typename t_AccessibleByGetType, ssize_t t_MaxSplit = -1>
		using RSplitAnyInList = typename tag_detail::template RSplitHelperInList<Tag, t_AccessibleByGetType, TypeList<>, FindLastInList<t_AccessibleByGetType>(), 0, t_MaxSplit>::type;

		template<typename t_PredType, ssize_t t_MaxSplit = -1>
		using RSplitAnyOf = typename tag_detail::template RSplitHelperAnyOf<Tag, t_PredType, TypeList<>, FindLastOf<t_PredType>(), 0, t_MaxSplit>::type;

		template<typename t_PredType, ssize_t t_MaxSplit = -1>
		using RSplitAnyNotOf = typename tag_detail::template RSplitHelperAnyNotOf<Tag, t_PredType, TypeList<>, FindLastNotOf<t_PredType>(), 0, t_MaxSplit>::type;

		template<bool t_KeepEnds = false>
		using SplitLines = typename tag_detail::template SplitLinesHelper<Tag, TypeList<>, FindFirstOf<sprawl::IsLineEnding>(), Substring<FindFirstOf<sprawl::IsLineEnding>()>::template FindFirstNotOf<sprawl::IsLineEnding>(), t_KeepEnds>::type;

		template<ssize_t t_Idx, typename t_OtherTagType>
		using Insert = typename Substring<0, t_Idx>::template Append<t_OtherTagType>::template Append<Substring<t_Idx>>;

		template<ssize_t t_Length>
		static constexpr bool EqualTo(char const (&str)[t_Length])
		{
			return t_Length - 1 == Tag::length ? equalTo_(0, length, 0, str, t_Chars...) : false;
		}

		template<typename t_OtherTagType>
		static constexpr bool EqualTo()
		{
			return std::is_same<Tag, t_OtherTagType>::value;
		}

		template<typename t_HashType = Murmur3<0>>
		static constexpr auto Hash() -> decltype(t_HashType::template Hash<t_Chars...>::value)
		{
			return t_HashType::template Hash<t_Chars...>::value;
		}

		template<ssize_t t_Start, ssize_t t_End = t_Len, ssize_t t_Interval = 1>
		using Slice = typename detail::SliceTag<
			Tag, 
			Tag<0>, 
			(t_Start >= t_Len ? t_Len - 1 : t_Start < 0 ? 0 : t_Start), 
			(t_End > t_Len ? t_Len : t_End < -1 ? -1 : t_End), 
			t_Interval, 
			(t_Start >= t_Len ? t_Len - 1 : t_Start < 0 ? 0 : t_Start),
			((t_Start < t_End ? t_Start < t_End : t_Start > t_End) && ((t_End - t_Start)/t_Interval) > 0)
		>::type;
	private:
		template<size_t t_Length>
		static constexpr bool equalTo_(ssize_t /*idx*/, ssize_t /*length_*/, ssize_t /*offset*/, char const (&/*str*/)[t_Length])
		{
			return t_Length == 1 && Tag::length == 0;
		}

		template<size_t t_Length>
		static constexpr bool equalTo_(ssize_t idx, ssize_t length_, ssize_t offset, char const (&str)[t_Length], char compareChar)
		{
			return offset > 0 ? false : idx >= length_ ? true : str[idx] == compareChar;
		}
		template<size_t t_Length, typename t_FirstCharType, typename... t_MorCharTypes>
		static constexpr bool equalTo_(ssize_t idx, ssize_t length_, ssize_t offset, char const (&str)[t_Length], t_FirstCharType compareChar, t_MorCharTypes... moreChars)
		{
			return
				offset > 0
				?
				equalTo_(idx, length_, offset - 1, str, moreChars...)
				:
				idx >= length_
				?
				true
				:
				str[idx] == compareChar ? equalTo_(idx + 1, length_, offset, str, moreChars...) : false;
		}

		template<size_t t_Length>
		static constexpr ssize_t find_(ssize_t idx, ssize_t start, size_t end, char const (&str)[t_Length], char compareChar)
		{
			return
				idx + t_Length - 1 > end
				?
				-1
				:
				idx >= start
				?
				equalTo_(0, t_Length - 1, 0, str, compareChar)
				?
				idx
				:
				-1
				:
				-1;
		}

		template<size_t t_Length, typename t_FirstCharType, typename... t_MorCharTypes>
		static constexpr ssize_t find_(ssize_t idx, ssize_t start, size_t end, char const (&str)[t_Length], t_FirstCharType compareChar, t_MorCharTypes... moreChars)
		{
			return
				idx + t_Length - 1 > end
				?
				-1
				:
				idx >= start
				?
				equalTo_(0, t_Length - 1, 0, str, compareChar, moreChars...)
				?
				idx
				:
				find_(idx + 1, start, end, str, moreChars...)
				:
				find_(idx + 1, start, end, str, moreChars...);
		}

		template<size_t t_Length>
		static constexpr ssize_t rfind_(ssize_t idx, ssize_t start, size_t end, char const (&str)[t_Length], char compareChar)
		{
			return
				idx + t_Length - 1 > end
				?
				-1
				:
				idx >= start
				?
				equalTo_(0, t_Length - 1, 0, str, compareChar)
				?
				idx
				:
				-1
				:
				-1;
		}

		template<size_t t_Length, typename t_FirstCharType, typename... t_MoreCharTypes>
		static constexpr ssize_t rfind_(ssize_t idx, ssize_t start, size_t end, char const (&str)[t_Length], t_FirstCharType compareChar, t_MoreCharTypes... moreChars)
		{
			return
				idx + t_Length - 1 > end
				?
				-1
				:
				idx >= start
				?
				rfind_(idx + 1, start, end, str, moreChars...) != -1
				?
				rfind_(idx + 1, start, end, str, moreChars...)
				:
				equalTo_(0, t_Length - 1, 0, str, compareChar, moreChars...)
				?
				idx
				:
				-1
				:
				rfind_(idx + 1, start, end, str, moreChars...);
		}

		template<size_t t_Length>
		static constexpr bool isOneOf_(char const (&str)[t_Length], char compareChar, size_t idx)
		{
			return idx == t_Length ? false : compareChar == str[idx] ? true : isOneOf_(str, compareChar, idx + 1);
		}

		template<size_t t_Length>
		static constexpr ssize_t findFirstOf_(ssize_t idx, ssize_t start, ssize_t end, char const (&str)[t_Length], char compareChar)
		{
			return
				idx >= end
				?
				-1
				:
				idx >= start
				?
				isOneOf_(str, compareChar, 0)
				?
				idx
				:
				-1
				:
				-1;
		}

		template<size_t t_Length, typename t_FirstCharType, typename... t_MorCharTypes>
		static constexpr ssize_t findFirstOf_(ssize_t idx, ssize_t start, ssize_t end, char const (&str)[t_Length], t_FirstCharType compareChar, t_MorCharTypes... moreChars)
		{
			return
				idx >= end
				?
				-1
				:
				idx >= start
				?
				isOneOf_(str, compareChar, 0)
				?
				idx
				:
				findFirstOf_(idx + 1, start, end, str, moreChars...)
				:
				findFirstOf_(idx + 1, start, end, str, moreChars...);
		}

		template<size_t t_Length>
		static constexpr ssize_t findLastOf_(ssize_t idx, ssize_t start, ssize_t end, char const (&str)[t_Length], char compareChar)
		{
			return
				idx >= end
				?
				-1
				:
				idx >= start
				?
				isOneOf_(str, compareChar, 0)
				?
				idx
				:
				-1
				:
				-1;
		}

		template<size_t t_Length, typename t_FirstCharType, typename... t_MoreCharTypes>
		static constexpr ssize_t findLastOf_(ssize_t idx, ssize_t start, ssize_t end, char const (&str)[t_Length], t_FirstCharType compareChar, t_MoreCharTypes... moreChars)
		{
			return
				idx >= end
				?
				-1
				:
				idx >= start
				?
				findLastOf_(idx + 1, start, end, str, moreChars...) != -1
				?
				findLastOf_(idx + 1, start, end, str, moreChars...)
				:
				isOneOf_(str, compareChar, 0)
				?
				idx
				:
				-1
				:
				findLastOf_(idx + 1, start, end, str, moreChars...);
		}

		template<size_t t_Length>
		static constexpr ssize_t findFirstNotOf_(ssize_t idx, ssize_t start, ssize_t end, char const (&str)[t_Length], char compareChar)
		{
			return
				idx >= end
				?
				-1
				:
				idx >= start
				?
				(!isOneOf_(str, compareChar, 0))
				?
				idx
				:
				-1
				:
				-1;
		}

		template<size_t t_Length, typename t_FirstCharType, typename... t_MorCharTypes>
		static constexpr ssize_t findFirstNotOf_(ssize_t idx, ssize_t start, ssize_t end, char const (&str)[t_Length], t_FirstCharType compareChar, t_MorCharTypes... moreChars)
		{
			return
				idx >= end
				?
				-1
				:
				idx >= start
				?
				(!isOneOf_(str, compareChar, 0))
				?
				idx
				:
				findFirstNotOf_(idx + 1, start, end, str, moreChars...)
				:
				findFirstNotOf_(idx + 1, start, end, str, moreChars...);
		}

		template<size_t t_Length>
		static constexpr ssize_t findLastNotOf_(ssize_t idx, ssize_t start, ssize_t end, char const (&str)[t_Length], char compareChar)
		{
			return
				idx >= end
				?
				-1
				:
				idx >= start
				?
				(!isOneOf_(str, compareChar, 0))
				?
				idx
				:
				-1
				:
				-1;
		}

		template<size_t t_Length, typename t_FirstCharType, typename... t_MoreCharTypes>
		static constexpr ssize_t findLastNotOf_(ssize_t idx, ssize_t start, ssize_t end, char const (&str)[t_Length], t_FirstCharType compareChar, t_MoreCharTypes... moreChars)
		{
			return
				idx >= end
				?
				-1
				:
				idx >= start
				?
				findLastNotOf_(idx + 1, start, end, str, moreChars...) != -1
				?
				findLastNotOf_(idx + 1, start, end, str, moreChars...)
				:
				(!isOneOf_(str, compareChar, 0))
				?
				idx
				:
				-1
				:
				findLastNotOf_(idx + 1, start, end, str, moreChars...);
		}
	};

	template<ssize_t t_Len, char... t_Chars>
	CONSTEXPR_ARRAY char Tag<t_Len, t_Chars...>::name[t_Len + 1] SPRAWL_CONSTEXPR_OUT_OF_CLASS_INIT({ t_Chars..., '\0' });

	namespace detail
	{
		template<typename t_Type>
		struct TypeToString
		{
		private:
			struct NameSize
			{
				char const* name;
				size_t size;
				constexpr NameSize(char const* name_, size_t size_) : name(name_), size(size_) {}
			};

#if defined(_MSC_VER) && !defined(__clang__)
			static constexpr size_t prefix_size = sizeof("sprawl::detail::TypeToString<") - 1;
			static constexpr size_t postfix_size = sizeof(">::f") - 1;
#else
			static constexpr size_t prefix_size = sizeof("static sprawl::detail::TypeToString::NameSize sprawl::detail::TypeToString<") - 1;
			static constexpr size_t postfix_size = sizeof(">::f() [t_Type = ]") - 1;
#endif

			static constexpr NameSize f()
			{
#if defined(_MSC_VER) && !defined(__clang__)
				return{ __FUNCTION__ + prefix_size, sizeof(__FUNCTION__) - prefix_size - postfix_size };
#else
				return{ __PRETTY_FUNCTION__ + prefix_size, sizeof(__PRETTY_FUNCTION__) - prefix_size - postfix_size - ((sizeof(__PRETTY_FUNCTION__) - prefix_size - postfix_size) / 2) };
#endif
			}

			static constexpr NameSize nameSize = f();
		public:
			//Gotta do this the hard way since we can't sizeof()...
			typedef typename ::sprawl::detail::TagWrapper<
				::sprawl::detail::SizeChecker<nameSize.size - 1>::value, 1,
				::sprawl::Tag<0>,
				::sprawl::detail::IsPositive<nameSize.size - 1>::value,
				true,
				SPRAWL_CHR_MAX_MACRO(nameSize.name, nameSize.size, 0)
			>::type nakedType;

#if defined(_MSC_VER) && !defined(__clang__)
			// Consistency - msvc adds 'struct' or 'class' to the typename, clang/gcc do not.
			// Also, msvc doesn't include spaces after commas, clang/gcc do.
			// Also, msvc will add a space after every >, while clang/gcc will only put it between them - for simplicity, we're removing all spaces that follow >
			typedef typename If<nakedType::StartsWith("struct "), typename nakedType::template ReplaceAt<0, 7, SPRAWL_TAG("")>>
				::template ElseIf<nakedType::StartsWith("class "), typename nakedType::template ReplaceAt<0, 6, SPRAWL_TAG("")>>
				::template Else<nakedType>
				::template type<::sprawl::UnmatchedIfSequence>
				::template Replace<SPRAWL_TAG(","), SPRAWL_TAG(", ")>
				::template Replace<SPRAWL_TAG("> "), SPRAWL_TAG(">")>
				::template Replace<SPRAWL_TAG(" class "), SPRAWL_TAG(" ")>
				::template Replace<SPRAWL_TAG(" struct "), SPRAWL_TAG(" ")>
				::template Replace<SPRAWL_TAG("<class "), SPRAWL_TAG("<")>
				::template Replace<SPRAWL_TAG("<struct "), SPRAWL_TAG("<")>
				type;
#else
			typedef typename nakedType::template Replace<SPRAWL_TAG("> "), SPRAWL_TAG(">")> type;
#endif
		};

		template<typename t_Type, t_Type t_Value, bool t_IsSingleDigit = (t_Value >= 0 && t_Value < 10), bool t_IsNegative = (t_Value < 0)>
			struct TagFromInt
			{
				typedef typename TagFromInt<t_Type, t_Value / 10>::type::template Append<Tag<1, char(t_Value % 10) + '0'>> type;
			};

			template<typename t_Type, t_Type t_Value>
			struct TagFromInt<t_Type, t_Value, true, false>
			{
				typedef Tag<1, char(t_Value) + '0'> type;
			};

			template<typename t_Type, t_Type t_Value>
			struct TagFromInt<t_Type, t_Value, false, true>
			{
				typedef typename Tag<1, '-'>::Append<typename TagFromInt<t_Type, 0 - t_Value>::type> type;
			};

			template<typename t_Type, t_Type t_Value, bool t_IsSingleDigit = (t_Value >= 0 && t_Value < 10)>
				struct TagFromUInt
				{
					typedef typename TagFromUInt<t_Type, t_Value / 10>::type::template Append<Tag<1, char(t_Value % 10) + '0'>> type;
				};

				template<typename t_Type, t_Type t_Value>
				struct TagFromUInt<t_Type, t_Value, true>
				{
					typedef Tag<1, char(t_Value) + '0'> type;
				};

				template<bool t_Value>
				struct TagFromBool
				{
					typedef Tag<4, 't', 'r', 'u', 'e'> type;
				};

				template<>
				struct TagFromBool<false>
				{
					typedef Tag<5, 'f', 'a', 'l', 's', 'e'> type;
				};
	}
	template<typename t_Type>
	using TypeName = typename detail::TypeToString<t_Type>::type;

	template<typename t_Type>
	struct TagFrom;

	template<>
	struct TagFrom<char>
	{
		template<char t_Char>
		using FromValue = Tag<1, t_Char>;
	};

	template<> struct TagFrom<signed char> { template<signed char t_Value> using FromValue = typename detail::TagFromInt<signed char, t_Value>::type; };
	template<> struct TagFrom<short      > { template<short t_Value      > using FromValue = typename detail::TagFromInt<short, t_Value>::type; };
	template<> struct TagFrom<int        > { template<int t_Value        > using FromValue = typename detail::TagFromInt<int, t_Value>::type; };
	template<> struct TagFrom<long       > { template<long t_Value       > using FromValue = typename detail::TagFromInt<long, t_Value>::type; };
	template<> struct TagFrom<long long  > { template<long long t_Value  > using FromValue = typename detail::TagFromInt<long long, t_Value>::type; };

	template<> struct TagFrom<unsigned char     > { template<unsigned char t_Value     > using FromValue = typename detail::TagFromUInt<unsigned char, t_Value>::type; };
	template<> struct TagFrom<unsigned short    > { template<unsigned short t_Value    > using FromValue = typename detail::TagFromUInt<unsigned short, t_Value>::type; };
	template<> struct TagFrom<unsigned int      > { template<unsigned int t_Value      > using FromValue = typename detail::TagFromUInt<unsigned int, t_Value>::type; };
	template<> struct TagFrom<unsigned long     > { template<unsigned long t_Value     > using FromValue = typename detail::TagFromUInt<unsigned long, t_Value>::type; };
	template<> struct TagFrom<unsigned long long> { template<unsigned long long t_Value> using FromValue = typename detail::TagFromUInt<unsigned long long, t_Value>::type; };

	template<> struct TagFrom<bool> { template<bool t_Value> using FromValue = typename detail::TagFromBool<t_Value>::type; };

	template<>
	struct TagFrom<std::nullptr_t>
	{
		template<std::nullptr_t value>
		using FromValue = Tag<6, '(', 'n', 'u', 'l', 'l', ')'>;
	};
}
# Change User Description Committed
#3 20951 ShadauxCat - Reworked ConcurrentQueue::Dequeue to be a lot faster and wait-free
- Added constexpr constructor for sprawl tag
- Added support for specifying base for int-to-tag conversion
- Added ability to force poolallocator to pass through to malloc
- Added a helper class that will eventually be used in StringBuilder for faster int-to-string conversion

#review-20952 post-commit
#2 19912 ShadauxCat Fix various linux warnings and errors under clang 3.6

#review-19913
#1 19906 ShadauxCat - Added tag, compile time string type
- Since tag requires visual studio 2015, removed compatibility code for earlier versions of visual studio
- Improved compiler detection
- Added endianness detection
- Added template if/else helper
- Fixed bug with murmur3 64 bit
- Added seed argument for murmur3

#review-19907