diff --git a/.gitignore b/.gitignore index 1244f5ac..468fbda5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ eastl_build_out build_bench bench.bat build.bat +.p4config ## CMake generated files CMakeCache.txt diff --git a/include/EASTL/any.h b/include/EASTL/any.h index 7f14ae74..395b3346 100644 --- a/include/EASTL/any.h +++ b/include/EASTL/any.h @@ -330,8 +330,10 @@ namespace eastl storage_handler_ptr m_handler; public: - // TODO(rparolin): renable constexpr - // EA_CONSTEXPR + #ifndef EA_COMPILER_GNUC + // TODO(rparolin): renable constexpr for GCC + EA_CONSTEXPR + #endif any() EA_NOEXCEPT : m_storage(), m_handler(nullptr) {} diff --git a/include/EASTL/chrono.h b/include/EASTL/chrono.h index 8f9be94b..35c6919b 100644 --- a/include/EASTL/chrono.h +++ b/include/EASTL/chrono.h @@ -553,7 +553,7 @@ namespace chrono /////////////////////////////////////////////////////////////////////////////// // Internal::GetTicks /////////////////////////////////////////////////////////////////////////////// - uint64_t GetTicks() + inline uint64_t GetTicks() { #if defined EA_PLATFORM_MICROSOFT uint64_t t; diff --git a/include/EASTL/core_allocator_adapter.h b/include/EASTL/core_allocator_adapter.h index 3fa66b75..30c431df 100644 --- a/include/EASTL/core_allocator_adapter.h +++ b/include/EASTL/core_allocator_adapter.h @@ -255,10 +255,13 @@ namespace EA template inline CoreAllocatorAdapter& CoreAllocatorAdapter::operator=(const CoreAllocatorAdapter& x) { - // In order to be consistent with EASTL's allocator implementation, - // we don't copy the name from the source object. mpCoreAllocator = x.mpCoreAllocator; mnFlags = x.mnFlags; + + #if EASTL_NAME_ENABLED + mpName = x.mpName; + #endif + return *this; } diff --git a/include/EASTL/internal/char_traits.h b/include/EASTL/internal/char_traits.h new file mode 100644 index 00000000..5d54caaa --- /dev/null +++ b/include/EASTL/internal/char_traits.h @@ -0,0 +1,422 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements similar functionality to char_traits which is part of +// the C++ standard STL library specification. This is intended for internal +// EASTL use only. Functionality can be accessed through the eastl::string or +// eastl::string_view types. +// +// http://en.cppreference.com/w/cpp/string/char_traits +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_CHAR_TRAITS_H +#define EASTL_CHAR_TRAITS_H + +EA_ONCE() + +#include + +namespace eastl +{ + /////////////////////////////////////////////////////////////////////////////// + /// DecodePart + /// + /// These implement UTF8/UCS2/UCS4 encoding/decoding. + /// + EASTL_API bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); + EASTL_API bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); + EASTL_API bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); + + EASTL_API bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); + EASTL_API bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); + EASTL_API bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); + + EASTL_API bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); + EASTL_API bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); + EASTL_API bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); + + EASTL_API bool DecodePart(const int*& pSrc, const int* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); + EASTL_API bool DecodePart(const int*& pSrc, const int* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); + EASTL_API bool DecodePart(const int*& pSrc, const int* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); + + #if EA_WCHAR_UNIQUE + bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); + bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); + bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); + + bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd); + bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd); + bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd); + #endif + + + #if EA_WCHAR_UNIQUE + inline bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd) + { + EA_DISABLE_SN_WARNING(1785) + #if (EA_WCHAR_SIZE == 2) + return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); + #elif (EA_WCHAR_SIZE == 4) + return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); + #endif + EA_RESTORE_SN_WARNING() + } + + inline bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd) + { + EA_DISABLE_SN_WARNING(1785) + #if (EA_WCHAR_SIZE == 2) + return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); + #elif (EA_WCHAR_SIZE == 4) + return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); + #endif + EA_RESTORE_SN_WARNING() + } + + inline bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd) + { + EA_DISABLE_SN_WARNING(1785) + #if (EA_WCHAR_SIZE == 2) + return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); + #elif (EA_WCHAR_SIZE == 4) + return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); + #endif + EA_RESTORE_SN_WARNING() + } + + inline bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd) + { + EA_DISABLE_SN_WARNING(1785) + #if (EA_WCHAR_SIZE == 2) + return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); + #elif (EA_WCHAR_SIZE == 4) + return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); + #endif + EA_RESTORE_SN_WARNING() + } + + inline bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd) + { + EA_DISABLE_SN_WARNING(1785) + #if (EA_WCHAR_SIZE == 2) + return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); + #elif (EA_WCHAR_SIZE == 4) + return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); + #endif + EA_RESTORE_SN_WARNING() + } + + inline bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd) + { + EA_DISABLE_SN_WARNING(1785) + #if (EA_WCHAR_SIZE == 2) + return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); + #elif (EA_WCHAR_SIZE == 4) + return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); + #endif + EA_RESTORE_SN_WARNING() + } + #endif + + /////////////////////////////////////////////////////////////////////////////// + // 'char traits' functionality + // + inline char8_t CharToLower(char8_t c) + { return (char8_t)tolower((uint8_t)c); } + + inline char16_t CharToLower(char16_t c) + { if((unsigned)c <= 0xff) return (char16_t)tolower((uint8_t)c); return c; } + + inline char32_t CharToLower(char32_t c) + { if((unsigned)c <= 0xff) return (char32_t)tolower((uint8_t)c); return c; } + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline wchar_t CharToLower(wchar_t c) + { if((unsigned)c <= 0xff) return (wchar_t)tolower((uint8_t)c); return c; } + #endif + + + inline char8_t CharToUpper(char8_t c) + { return (char8_t)toupper((uint8_t)c); } + + inline char16_t CharToUpper(char16_t c) + { if((unsigned)c <= 0xff) return (char16_t)toupper((uint8_t)c); return c; } + + inline char32_t CharToUpper(char32_t c) + { if((unsigned)c <= 0xff) return (char32_t)toupper((uint8_t)c); return c; } + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline wchar_t CharToUpper(wchar_t c) + { if((unsigned)c <= 0xff) return (wchar_t)toupper((uint8_t)c); return c; } + #endif + + + template + int Compare(const T* p1, const T* p2, size_t n) + { + for(; n > 0; ++p1, ++p2, --n) + { + if(*p1 != *p2) + return (static_cast::type>(*p1) < + static_cast::type>(*p2)) ? -1 : 1; + } + return 0; + } + + inline int Compare(const char8_t* p1, const char8_t* p2, size_t n) + { + return memcmp(p1, p2, n); + } + + template + inline int CompareI(const T* p1, const T* p2, size_t n) + { + for(; n > 0; ++p1, ++p2, --n) + { + const T c1 = CharToLower(*p1); + const T c2 = CharToLower(*p2); + + if(c1 != c2) + return (static_cast::type>(c1) < + static_cast::type>(c2)) ? -1 : 1; + } + return 0; + } + + + inline const char8_t* Find(const char8_t* p, char8_t c, size_t n) + { + return (const char8_t*)memchr(p, c, n); + } + + inline const char16_t* Find(const char16_t* p, char16_t c, size_t n) + { + for(; n > 0; --n, ++p) + { + if(*p == c) + return p; + } + + return NULL; + } + + inline const char32_t* Find(const char32_t* p, char32_t c, size_t n) + { + for(; n > 0; --n, ++p) + { + if(*p == c) + return p; + } + + return NULL; + } + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline const wchar_t* Find(const wchar_t* p, wchar_t c, size_t n) + { + for(; n > 0; --n, ++p) + { + if(*p == c) + return p; + } + + return NULL; + } + #endif + + inline size_t CharStrlen(const char8_t* p) + { + #if defined(_MSC_VER) || defined(__GNUC__) + return strlen(p); + #else + const char8_t* pCurrent = p; + while(*pCurrent) + ++pCurrent; + return (size_t)(pCurrent - p); + #endif + } + + inline size_t CharStrlen(const char16_t* p) + { + const char16_t* pCurrent = p; + while(*pCurrent) + ++pCurrent; + return (size_t)(pCurrent - p); + } + + inline size_t CharStrlen(const char32_t* p) + { + const char32_t* pCurrent = p; + while(*pCurrent) + ++pCurrent; + return (size_t)(pCurrent - p); + } + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline size_t CharStrlen(const wchar_t* p) + { + const wchar_t* pCurrent = p; + while(*pCurrent) + ++pCurrent; + return (size_t)(pCurrent - p); + } + #endif + + template + inline T* CharStringUninitializedCopy(const T* pSource, const T* pSourceEnd, T* pDestination) + { + memmove(pDestination, pSource, (size_t)(pSourceEnd - pSource) * sizeof(T)); + return pDestination + (pSourceEnd - pSource); + } + + template + inline const T* CharTypeStringFindFirstOf(const T* p1Begin, const T* p1End, const T* p2Begin, const T* p2End) + { + for (; p1Begin != p1End; ++p1Begin) + { + for (const T* pTemp = p2Begin; pTemp != p2End; ++pTemp) + { + if (*p1Begin == *pTemp) + return p1Begin; + } + } + return p1End; + } + + template + inline const T* CharTypeStringRFindFirstNotOf(const T* p1RBegin, const T* p1REnd, const T* p2Begin, const T* p2End) + { + for (; p1RBegin != p1REnd; --p1RBegin) + { + const T* pTemp; + for (pTemp = p2Begin; pTemp != p2End; ++pTemp) + { + if (*(p1RBegin - 1) == *pTemp) + break; + } + if (pTemp == p2End) + return p1RBegin; + } + return p1REnd; + } + + template + inline const T* CharTypeStringFindFirstNotOf(const T* p1Begin, const T* p1End, const T* p2Begin, const T* p2End) + { + for (; p1Begin != p1End; ++p1Begin) + { + const T* pTemp; + for (pTemp = p2Begin; pTemp != p2End; ++pTemp) + { + if (*p1Begin == *pTemp) + break; + } + if (pTemp == p2End) + return p1Begin; + } + return p1End; + } + + template + inline const T* CharTypeStringRFindFirstOf(const T* p1RBegin, const T* p1REnd, const T* p2Begin, const T* p2End) + { + for (; p1RBegin != p1REnd; --p1RBegin) + { + for (const T* pTemp = p2Begin; pTemp != p2End; ++pTemp) + { + if (*(p1RBegin - 1) == *pTemp) + return p1RBegin; + } + } + return p1REnd; + } + + template + inline const T* CharTypeStringRFind(const T* pRBegin, const T* pREnd, const T c) + { + while (pRBegin > pREnd) + { + if (*(pRBegin - 1) == c) + return pRBegin; + --pRBegin; + } + return pREnd; + } + + + inline char8_t* CharStringUninitializedFillN(char8_t* pDestination, size_t n, const char8_t c) + { + if(n) // Some compilers (e.g. GCC 4.3+) generate a warning (which can't be disabled) if you call memset with a size of 0. + memset(pDestination, (uint8_t)c, (size_t)n); + return pDestination + n; + } + + inline char16_t* CharStringUninitializedFillN(char16_t* pDestination, size_t n, const char16_t c) + { + char16_t* pDest16 = pDestination; + const char16_t* const pEnd = pDestination + n; + while(pDest16 < pEnd) + *pDest16++ = c; + return pDestination + n; + } + + inline char32_t* CharStringUninitializedFillN(char32_t* pDestination, size_t n, const char32_t c) + { + char32_t* pDest32 = pDestination; + const char32_t* const pEnd = pDestination + n; + while(pDest32 < pEnd) + *pDest32++ = c; + return pDestination + n; + } + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline wchar_t* CharStringUninitializedFillN(wchar_t* pDestination, size_t n, const wchar_t c) + { + wchar_t* pDest32 = pDestination; + const wchar_t* const pEnd = pDestination + n; + while(pDest32 < pEnd) + *pDest32++ = c; + return pDestination + n; + } + #endif + + inline char8_t* CharTypeAssignN(char8_t* pDestination, size_t n, char8_t c) + { + if(n) // Some compilers (e.g. GCC 4.3+) generate a warning (which can't be disabled) if you call memset with a size of 0. + return (char8_t*)memset(pDestination, c, (size_t)n); + return pDestination; + } + + inline char16_t* CharTypeAssignN(char16_t* pDestination, size_t n, char16_t c) + { + char16_t* pDest16 = pDestination; + const char16_t* const pEnd = pDestination + n; + while(pDest16 < pEnd) + *pDest16++ = c; + return pDestination; + } + + inline char32_t* CharTypeAssignN(char32_t* pDestination, size_t n, char32_t c) + { + char32_t* pDest32 = pDestination; + const char32_t* const pEnd = pDestination + n; + while(pDest32 < pEnd) + *pDest32++ = c; + return pDestination; + } + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline wchar_t* CharTypeAssignN(wchar_t* pDestination, size_t n, wchar_t c) + { + wchar_t* pDest32 = pDestination; + const wchar_t* const pEnd = pDestination + n; + while(pDest32 < pEnd) + *pDest32++ = c; + return pDestination; + } + #endif +} // namespace eastl + +#endif // EASTL_CHAR_TRAITS_H diff --git a/include/EASTL/internal/config.h b/include/EASTL/internal/config.h index bfc00960..60c02ef3 100644 --- a/include/EASTL/internal/config.h +++ b/include/EASTL/internal/config.h @@ -105,8 +105,8 @@ /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_VERSION - #define EASTL_VERSION "3.04.00" - #define EASTL_VERSION_N 30400 + #define EASTL_VERSION "3.05.00" + #define EASTL_VERSION_N 30500 #endif diff --git a/include/EASTL/internal/function.h b/include/EASTL/internal/function.h index a9e21124..5466338c 100644 --- a/include/EASTL/internal/function.h +++ b/include/EASTL/internal/function.h @@ -74,7 +74,7 @@ For more information, please refer to // This workaround exists because on MSVC the "is_nothrow_move_constructible" type trait does not function as // expected. It incorrectly flags the coping/moving of a pointer to the callable as being able to throw an exception. // We can remove this workaround when the "is_nothrow_move_constructible" type trait functions for all Microsoft -// platforms and we being testing it again in EASTLs unit tests. +// platforms and we begin testing it again in EASTLs unit tests. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(EA_PLATFORM_MICROSOFT) #define EASTL_INTERNAL_FUNCTION_ARE_TYPETRAITS_FUNCTIONAL 0 @@ -88,18 +88,34 @@ namespace eastl /// /// Defines a default container name in the absence of a user-provided name. /// - #ifndef EASTL_VECTOR_DEFAULT_NAME + #ifndef EASTL_FUNCTION_DEFAULT_NAME #define EASTL_FUNCTION_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " function" // Unless the user overrides something, this is "EASTL function". #endif - - /// EASTL_VECTOR_DEFAULT_ALLOCATOR + /// EASTL_FUNCTION_DEFAULT_ALLOCATOR /// - #ifndef EASTL_VECTOR_DEFAULT_ALLOCATOR + #ifndef EASTL_FUNCTION_DEFAULT_ALLOCATOR #define EASTL_FUNCTION_DEFAULT_ALLOCATOR allocator_type(EASTL_FUNCTION_DEFAULT_NAME) #endif + /// EASTL_FUNCTION_DEFAULT_CAPTURE_SSO_SIZE + /// + /// Defines the size of the SSO buffer which is used to hold the specified capture state of the callable. + /// + #ifndef EASTL_FUNCTION_DEFAULT_CAPTURE_SSO_SIZE + #define EASTL_FUNCTION_DEFAULT_CAPTURE_SSO_SIZE (2 * sizeof(void*)) + #endif + + /// EASTL_FUNCTION_DEFAULT_ALLOCATOR_SSO_SIZE + /// + /// Defines the size of the SSO buffer which is used to hold the specified allocator type. + /// + #ifndef EASTL_FUNCTION_DEFAULT_ALLOCATOR_SSO_SIZE + #define EASTL_FUNCTION_DEFAULT_ALLOCATOR_SSO_SIZE (2 * sizeof(void*)) + #endif + + template struct force_function_heap_allocation : public eastl::false_type {}; @@ -114,16 +130,24 @@ namespace detail struct functor_storage_type { - protected: - size_t padding_first; - size_t padding_second; + union + { + void* first; + char padding[EASTL_FUNCTION_DEFAULT_CAPTURE_SSO_SIZE]; + }; }; + static_assert(sizeof(functor_storage_type) >= EASTL_FUNCTION_DEFAULT_CAPTURE_SSO_SIZE, "capture storage size mismatch"); struct allocator_storage_type { - void* first; - void* second; + union + { + void* first; + char padding[EASTL_FUNCTION_DEFAULT_ALLOCATOR_SSO_SIZE]; + }; }; + static_assert(sizeof(allocator_storage_type) >= EASTL_FUNCTION_DEFAULT_ALLOCATOR_SSO_SIZE, "allocator storage size mismatch"); + struct empty_struct { }; @@ -141,10 +165,10 @@ namespace detail && sizeof(Allocator) <= sizeof(allocator_storage_type) // so that it will be aligned && eastl::alignment_of::value % eastl::alignment_of::value == 0 -#if EASTL_INTERNAL_FUNCTION_ARE_TYPETRAITS_FUNCTIONAL + #if EASTL_INTERNAL_FUNCTION_ARE_TYPETRAITS_FUNCTIONAL // so that we can offer noexcept move && eastl::is_nothrow_move_constructible::value -#endif + #endif // so that the user can override it && !force_function_heap_allocation::value; }; diff --git a/include/EASTL/optional.h b/include/EASTL/optional.h index 4bcf9797..2c4f7926 100644 --- a/include/EASTL/optional.h +++ b/include/EASTL/optional.h @@ -312,6 +312,15 @@ namespace eastl } } + inline void reset() + { + if (engaged) + { + destruct_value(); + engaged = false; + } + } + private: inline void construct_value(const value_type& v) @@ -320,15 +329,6 @@ namespace eastl inline void construct_value(value_type&& v) { ::new (eastl::addressof(val)) value_type(eastl::move(v)); } - inline void reset() - { - if(engaged) - { - destruct_value(); - engaged = false; - } - } - inline T* get_value_address() EASTL_OPTIONAL_NOEXCEPT { #if EASTL_EXCEPTIONS_ENABLED diff --git a/include/EASTL/string.h b/include/EASTL/string.h index 8d9e3714..618cc7e2 100644 --- a/include/EASTL/string.h +++ b/include/EASTL/string.h @@ -140,7 +140,7 @@ EA_RESTORE_GCC_WARNING() #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. #endif - +#include /////////////////////////////////////////////////////////////////////////////// // EASTL_STRING_EXPLICIT @@ -646,332 +646,8 @@ namespace eastl }; // basic_string - /////////////////////////////////////////////////////////////////////////////// - /// DecodePart - /// - /// These implement UTF8/UCS2/UCS4 encoding/decoding. - /// - EASTL_API bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); - EASTL_API bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); - EASTL_API bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); - - EASTL_API bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); - EASTL_API bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); - EASTL_API bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); - - EASTL_API bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); - EASTL_API bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); - EASTL_API bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); - - EASTL_API bool DecodePart(const int*& pSrc, const int* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); - EASTL_API bool DecodePart(const int*& pSrc, const int* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); - EASTL_API bool DecodePart(const int*& pSrc, const int* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); - - #if EA_WCHAR_UNIQUE - bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd); - bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd); - bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd); - - bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd); - bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd); - bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd); - #endif - - - #if EA_WCHAR_UNIQUE - inline bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char8_t*& pDest, char8_t* pDestEnd) - { - EA_DISABLE_SN_WARNING(1785) - #if (EA_WCHAR_SIZE == 2) - return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); - #elif (EA_WCHAR_SIZE == 4) - return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); - #endif - EA_RESTORE_SN_WARNING() - } - - inline bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char16_t*& pDest, char16_t* pDestEnd) - { - EA_DISABLE_SN_WARNING(1785) - #if (EA_WCHAR_SIZE == 2) - return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); - #elif (EA_WCHAR_SIZE == 4) - return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); - #endif - EA_RESTORE_SN_WARNING() - } - - inline bool DecodePart(const wchar_t*& pSrc, const wchar_t* pSrcEnd, char32_t*& pDest, char32_t* pDestEnd) - { - EA_DISABLE_SN_WARNING(1785) - #if (EA_WCHAR_SIZE == 2) - return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); - #elif (EA_WCHAR_SIZE == 4) - return DecodePart(reinterpret_cast(pSrc), reinterpret_cast(pSrcEnd), pDest, pDestEnd); - #endif - EA_RESTORE_SN_WARNING() - } - - inline bool DecodePart(const char8_t*& pSrc, const char8_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd) - { - EA_DISABLE_SN_WARNING(1785) - #if (EA_WCHAR_SIZE == 2) - return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); - #elif (EA_WCHAR_SIZE == 4) - return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); - #endif - EA_RESTORE_SN_WARNING() - } - - inline bool DecodePart(const char16_t*& pSrc, const char16_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd) - { - EA_DISABLE_SN_WARNING(1785) - #if (EA_WCHAR_SIZE == 2) - return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); - #elif (EA_WCHAR_SIZE == 4) - return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); - #endif - EA_RESTORE_SN_WARNING() - } - - inline bool DecodePart(const char32_t*& pSrc, const char32_t* pSrcEnd, wchar_t*& pDest, wchar_t* pDestEnd) - { - EA_DISABLE_SN_WARNING(1785) - #if (EA_WCHAR_SIZE == 2) - return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); - #elif (EA_WCHAR_SIZE == 4) - return DecodePart(pSrc, pSrcEnd, reinterpret_cast(pDest), reinterpret_cast(pDestEnd)); - #endif - EA_RESTORE_SN_WARNING() - } - #endif - - - /////////////////////////////////////////////////////////////////////////////// - // 'char traits' functionality - // - inline char8_t CharToLower(char8_t c) - { return (char8_t)tolower((uint8_t)c); } - inline char16_t CharToLower(char16_t c) - { if((unsigned)c <= 0xff) return (char16_t)tolower((uint8_t)c); return c; } - inline char32_t CharToLower(char32_t c) - { if((unsigned)c <= 0xff) return (char32_t)tolower((uint8_t)c); return c; } - - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - inline wchar_t CharToLower(wchar_t c) - { if((unsigned)c <= 0xff) return (wchar_t)tolower((uint8_t)c); return c; } - #endif - - - inline char8_t CharToUpper(char8_t c) - { return (char8_t)toupper((uint8_t)c); } - - inline char16_t CharToUpper(char16_t c) - { if((unsigned)c <= 0xff) return (char16_t)toupper((uint8_t)c); return c; } - - inline char32_t CharToUpper(char32_t c) - { if((unsigned)c <= 0xff) return (char32_t)toupper((uint8_t)c); return c; } - - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - inline wchar_t CharToUpper(wchar_t c) - { if((unsigned)c <= 0xff) return (wchar_t)toupper((uint8_t)c); return c; } - #endif - - - template - int Compare(const T* p1, const T* p2, size_t n) - { - for(; n > 0; ++p1, ++p2, --n) - { - if(*p1 != *p2) - return (static_cast::type>(*p1) < - static_cast::type>(*p2)) ? -1 : 1; - } - return 0; - } - - inline int Compare(const char8_t* p1, const char8_t* p2, size_t n) - { - return memcmp(p1, p2, n); - } - - template - inline int CompareI(const T* p1, const T* p2, size_t n) - { - for(; n > 0; ++p1, ++p2, --n) - { - const T c1 = CharToLower(*p1); - const T c2 = CharToLower(*p2); - - if(c1 != c2) - return (static_cast::type>(c1) < - static_cast::type>(c2)) ? -1 : 1; - } - return 0; - } - - - inline const char8_t* Find(const char8_t* p, char8_t c, size_t n) - { - return (const char8_t*)memchr(p, c, n); - } - - inline const char16_t* Find(const char16_t* p, char16_t c, size_t n) - { - for(; n > 0; --n, ++p) - { - if(*p == c) - return p; - } - - return NULL; - } - - inline const char32_t* Find(const char32_t* p, char32_t c, size_t n) - { - for(; n > 0; --n, ++p) - { - if(*p == c) - return p; - } - - return NULL; - } - - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - inline const wchar_t* Find(const wchar_t* p, wchar_t c, size_t n) - { - for(; n > 0; --n, ++p) - { - if(*p == c) - return p; - } - - return NULL; - } - #endif - - inline size_t CharStrlen(const char8_t* p) - { - #if defined(_MSC_VER) || defined(__GNUC__) - return strlen(p); - #else - const char8_t* pCurrent = p; - while(*pCurrent) - ++pCurrent; - return (size_t)(pCurrent - p); - #endif - } - - inline size_t CharStrlen(const char16_t* p) - { - const char16_t* pCurrent = p; - while(*pCurrent) - ++pCurrent; - return (size_t)(pCurrent - p); - } - - inline size_t CharStrlen(const char32_t* p) - { - const char32_t* pCurrent = p; - while(*pCurrent) - ++pCurrent; - return (size_t)(pCurrent - p); - } - - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - inline size_t CharStrlen(const wchar_t* p) - { - const wchar_t* pCurrent = p; - while(*pCurrent) - ++pCurrent; - return (size_t)(pCurrent - p); - } - #endif - - template - inline T* CharStringUninitializedCopy(const T* pSource, const T* pSourceEnd, T* pDestination) - { - memmove(pDestination, pSource, (size_t)(pSourceEnd - pSource) * sizeof(T)); - return pDestination + (pSourceEnd - pSource); - } - - - - - inline char8_t* CharStringUninitializedFillN(char8_t* pDestination, size_t n, const char8_t c) - { - if(n) // Some compilers (e.g. GCC 4.3+) generate a warning (which can't be disabled) if you call memset with a size of 0. - memset(pDestination, (uint8_t)c, (size_t)n); - return pDestination + n; - } - - inline char16_t* CharStringUninitializedFillN(char16_t* pDestination, size_t n, const char16_t c) - { - char16_t* pDest16 = pDestination; - const char16_t* const pEnd = pDestination + n; - while(pDest16 < pEnd) - *pDest16++ = c; - return pDestination + n; - } - - inline char32_t* CharStringUninitializedFillN(char32_t* pDestination, size_t n, const char32_t c) - { - char32_t* pDest32 = pDestination; - const char32_t* const pEnd = pDestination + n; - while(pDest32 < pEnd) - *pDest32++ = c; - return pDestination + n; - } - - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - inline wchar_t* CharStringUninitializedFillN(wchar_t* pDestination, size_t n, const wchar_t c) - { - wchar_t* pDest32 = pDestination; - const wchar_t* const pEnd = pDestination + n; - while(pDest32 < pEnd) - *pDest32++ = c; - return pDestination + n; - } - #endif - - inline char8_t* CharTypeAssignN(char8_t* pDestination, size_t n, char8_t c) - { - if(n) // Some compilers (e.g. GCC 4.3+) generate a warning (which can't be disabled) if you call memset with a size of 0. - return (char8_t*)memset(pDestination, c, (size_t)n); - return pDestination; - } - - inline char16_t* CharTypeAssignN(char16_t* pDestination, size_t n, char16_t c) - { - char16_t* pDest16 = pDestination; - const char16_t* const pEnd = pDestination + n; - while(pDest16 < pEnd) - *pDest16++ = c; - return pDestination; - } - - inline char32_t* CharTypeAssignN(char32_t* pDestination, size_t n, char32_t c) - { - char32_t* pDest32 = pDestination; - const char32_t* const pEnd = pDestination + n; - while(pDest32 < pEnd) - *pDest32++ = c; - return pDestination; - } - - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - inline wchar_t* CharTypeAssignN(wchar_t* pDestination, size_t n, wchar_t c) - { - wchar_t* pDest32 = pDestination; - const wchar_t* const pEnd = pDestination + n; - while(pDest32 < pEnd) - *pDest32++ = c; - return pDestination; - } - #endif /////////////////////////////////////////////////////////////////////////////// // basic_string diff --git a/include/EASTL/string_view.h b/include/EASTL/string_view.h new file mode 100644 index 00000000..9d40d36d --- /dev/null +++ b/include/EASTL/string_view.h @@ -0,0 +1,523 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements the eastl::string_view which is part of the C++ standard +// STL library specification. +// +// http://en.cppreference.com/w/cpp/header/string_view +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_STRING_VIEW_H +#define EASTL_STRING_VIEW_H + +EA_ONCE() + +#include +#include +#include + +EA_DISABLE_VC_WARNING(4814) + + + +namespace eastl +{ + template + class basic_string_view + { + public: + typedef basic_string_view this_type; + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T* iterator; + typedef const T* const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + typedef eastl_size_t size_type; + typedef ptrdiff_t difference_type; + + static const EA_CONSTEXPR size_type npos = size_type(-1); + + protected: + const_pointer mpBegin = nullptr; + size_type mnCount = 0; + + public: + // 21.4.2.1, construction and assignment + EA_CONSTEXPR basic_string_view() EA_NOEXCEPT : mpBegin(nullptr), mnCount(0) {} + EA_CONSTEXPR basic_string_view(const basic_string_view& other) EA_NOEXCEPT = default; + EA_CONSTEXPR basic_string_view(const T* s, size_type count) : mpBegin(s), mnCount(count) {} + EA_CONSTEXPR basic_string_view(const T* s) : mpBegin(s), mnCount(CharStrlen(s)) {} + basic_string_view& operator=(const basic_string_view& view) = default; + + // 21.4.2.2, iterator support + EA_CONSTEXPR const_iterator begin() const EA_NOEXCEPT { return mpBegin; } + EA_CONSTEXPR const_iterator cbegin() const EA_NOEXCEPT { return mpBegin; } + EA_CONSTEXPR const_iterator end() const EA_NOEXCEPT { return mpBegin + mnCount; } + EA_CONSTEXPR const_iterator cend() const EA_NOEXCEPT { return mpBegin + mnCount; } + EA_CONSTEXPR const_reverse_iterator rbegin() const EA_NOEXCEPT { return reverse_iterator(mpBegin + mnCount); } + EA_CONSTEXPR const_reverse_iterator crbegin() const EA_NOEXCEPT { return reverse_iterator(mpBegin + mnCount); } + EA_CONSTEXPR const_reverse_iterator rend() const EA_NOEXCEPT { return reverse_iterator(mpBegin); } + EA_CONSTEXPR const_reverse_iterator crend() const EA_NOEXCEPT { return reverse_iterator(mpBegin); } + + + // 21.4.2.4, element access + EA_CONSTEXPR const_pointer data() const { return mpBegin; } + EA_CONSTEXPR const_reference front() const + { + return [&] { EASTL_ASSERT_MSG(!empty(), "behavior is undefined if string_view is empty"); }(), mpBegin[0]; + } + + EA_CONSTEXPR const_reference back() const + { + return [&] { EASTL_ASSERT_MSG(!empty(), "behavior is undefined if string_view is empty"); }(), mpBegin[mnCount - 1]; + } + + EA_CONSTEXPR const_reference operator[](size_type pos) const + { + // As per the standard spec: No bounds checking is performed: the behavior is undefined if pos >= size(). + return mpBegin[pos]; + } + + EA_CPP14_CONSTEXPR const_reference at(size_type pos) const + { + #if EASTL_EXCEPTIONS_ENABLED + if(EASTL_UNLIKELY(pos >= mnCount)) + throw std::out_of_range("string_view::at -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(pos >= mnCount)) + EASTL_FAIL_MSG("string_view::at -- out of range"); + #endif + + return mpBegin[pos]; + } + + + // 21.4.2.3, capacity + EA_CONSTEXPR size_type size() const EA_NOEXCEPT { return mnCount; } + EA_CONSTEXPR size_type length() const EA_NOEXCEPT { return mnCount; } + EA_CONSTEXPR size_type max_size() const EA_NOEXCEPT { return numeric_limits::max(); } + EA_CONSTEXPR bool empty() const EA_NOEXCEPT { return mnCount == 0; } + + + // 21.4.2.5, modifiers + EA_CPP14_CONSTEXPR void swap(basic_string_view& v) + { + eastl::swap(mpBegin, v.mpBegin); + eastl::swap(mnCount, v.mnCount); + } + + EA_CPP14_CONSTEXPR void remove_prefix(size_type n) + { + EASTL_ASSERT_MSG(n <= mnCount, "behavior is undefined if moving past the end of the string"); + mpBegin += n; + mnCount -= n; + } + + EA_CPP14_CONSTEXPR void remove_suffix(size_type n) + { + EASTL_ASSERT_MSG(n <= mnCount, "behavior is undefined if moving past the end of the string"); + mnCount -= n; + } + + + // 21.4.2.6, string operations + size_type copy(T* pDestination, size_type count, size_type pos = 0) const + { + #if EASTL_EXCEPTIONS_ENABLED + if(EASTL_UNLIKELY(pos > mnCount)) + throw std::out_of_range("string_view::copy -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(pos > mnCount)) + EASTL_FAIL_MSG("string_view::copy -- out of range"); + #endif + + count = eastl::min(count, mnCount - pos); + auto* pResult = CharStringUninitializedCopy(mpBegin + pos, mpBegin + pos + count, pDestination); + *pResult = 0; // write null-terminator + return pResult - pDestination; + } + + EA_CPP14_CONSTEXPR basic_string_view substr(size_type pos = 0, size_type count = npos) const + { + #if EASTL_EXCEPTIONS_ENABLED + if(EASTL_UNLIKELY(pos > mnCount)) + throw std::out_of_range("string_view::substr -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(pos > mnCount)) + EASTL_FAIL_MSG("string_view::substr -- out of range"); + #endif + + count = eastl::min(count, mnCount - pos); + return this_type(mpBegin + pos, count); + } + + EA_CONSTEXPR int compare(basic_string_view sw) const EA_NOEXCEPT + { + return Compare(mpBegin, sw.data(), eastl::min_alt(size(), sw.size())); + } + + EA_CONSTEXPR int compare(size_type pos1, size_type count1, basic_string_view sw) const + { + return substr(pos1, count1).compare(sw); + } + + EA_CONSTEXPR int compare(size_type pos1, + size_type count1, + basic_string_view sw, + size_type pos2, + size_type count2) const + { + return substr(pos1, count1).compare(sw.substr(pos2, count2)); + } + + EA_CONSTEXPR int compare(const T* s) const { return compare(basic_string_view(s)); } + + EA_CONSTEXPR int compare(size_type pos1, size_type count1, const T* s) const + { + return substr(pos1, count1).compare(basic_string_view(s)); + } + + EA_CONSTEXPR int compare(size_type pos1, size_type count1, const T* s, size_type count2) const + { + return substr(pos1, count1).compare(basic_string_view(s, count2)); + } + + EA_CPP14_CONSTEXPR size_type find(basic_string_view sw, size_type pos = 0) const EA_NOEXCEPT + { + auto* pEnd = mpBegin + mnCount; + if (EASTL_LIKELY(((npos - sw.size()) >= pos) && (pos + sw.size()) <= mnCount)) + { + const value_type* const pTemp = eastl::search(mpBegin + pos, pEnd, sw.data(), sw.data() + sw.size()); + + if ((pTemp != pEnd) || (sw.size() == 0)) + return (size_type)(pTemp - mpBegin); + } + return npos; + } + + EA_CONSTEXPR size_type find(T c, size_type pos = 0) const EA_NOEXCEPT + { + return find(basic_string_view(&c, 1), pos); + } + + EA_CONSTEXPR size_type find(const T* s, size_type pos, size_type count) const + { + return find(basic_string_view(s, count), pos); + } + + EA_CONSTEXPR size_type find(const T* s, size_type pos = 0) const { return find(basic_string_view(s), pos); } + + EA_CONSTEXPR size_type rfind(basic_string_view sw, size_type pos = npos) const EA_NOEXCEPT + { + return rfind(sw.mpBegin, pos, sw.mnCount); + } + + EA_CPP14_CONSTEXPR size_type rfind(T c, size_type pos = npos) const EA_NOEXCEPT + { + if (EASTL_LIKELY(mnCount)) + { + const value_type* const pEnd = mpBegin + eastl::min_alt(mnCount - 1, pos) + 1; + const value_type* const pResult = CharTypeStringRFind(pEnd, mpBegin, c); + + if (pResult != mpBegin) + return (size_type)((pResult - 1) - mpBegin); + } + return npos; + } + + EA_CPP14_CONSTEXPR size_type rfind(const T* s, size_type pos, size_type n) const + { + // Disabled because it's not clear what values are valid for position. + // It is documented that npos is a valid value, though. We return npos and + // don't crash if postion is any invalid value. + //#if EASTL_ASSERT_ENABLED + // if(EASTL_UNLIKELY((position != npos) && (position > (size_type)(mpEnd - mpBegin)))) + // EASTL_FAIL_MSG("basic_string::rfind -- invalid position"); + //#endif + + // Note that a search for a zero length string starting at position = end() returns end() and not npos. + // Note by Paul Pedriana: I am not sure how this should behave in the case of n == 0 and position > size. + // The standard seems to suggest that rfind doesn't act exactly the same as find in that input position + // can be > size and the return value can still be other than npos. Thus, if n == 0 then you can + // never return npos, unlike the case with find. + if (EASTL_LIKELY(n <= mnCount)) + { + if (EASTL_LIKELY(n)) + { + const const_iterator pEnd = mpBegin + eastl::min_alt(mnCount - n, pos) + n; + const const_iterator pResult = CharTypeStringRSearch(mpBegin, pEnd, s, s + n); + + if (pResult != pEnd) + return (size_type)(pResult - mpBegin); + } + else + return eastl::min_alt(mnCount, pos); + } + return npos; + } + + EA_CONSTEXPR size_type rfind(const T* s, size_type pos = npos) const + { + return rfind(s, pos, (size_type)CharStrlen(s)); + } + + EA_CONSTEXPR size_type find_first_of(basic_string_view sw, size_type pos = 0) const EA_NOEXCEPT + { + return find_first_of(sw.mpBegin, pos, mnCount); + } + + EA_CONSTEXPR size_type find_first_of(T c, size_type pos = 0) const EA_NOEXCEPT { return find(c, pos); } + + EA_CPP14_CONSTEXPR size_type find_first_of(const T* s, size_type pos, size_type n) const + { + // If position is >= size, we return npos. + if (EASTL_LIKELY((pos < mnCount))) + { + const value_type* const pBegin = mpBegin + pos; + const value_type* const pEnd = mpBegin + mnCount; + const const_iterator pResult = CharTypeStringFindFirstOf(pBegin, pEnd, s, s + n); + + if (pResult != pEnd) + return (size_type)(pResult - mpBegin); + } + return npos; + } + + EA_CONSTEXPR size_type find_first_of(const T* s, size_type pos = 0) const + { + return find_first_of(s, pos, (size_type)CharStrlen(s)); + } + + EA_CONSTEXPR size_type find_last_of(basic_string_view sw, size_type pos = npos) const EA_NOEXCEPT + { + return find_last_of(sw.mpBegin, pos, sw.mnCount); + } + + EA_CONSTEXPR size_type find_last_of(T c, size_type pos = npos) const EA_NOEXCEPT { return rfind(c, pos); } + + EA_CPP14_CONSTEXPR size_type find_last_of(const T* s, size_type pos, size_type n) const + { + // If n is zero or position is >= size, we return npos. + if (EASTL_LIKELY(mnCount)) + { + const value_type* const pEnd = mpBegin + eastl::min_alt(mnCount - 1, pos) + 1; + const value_type* const pResult = CharTypeStringRFindFirstOf(pEnd, mpBegin, s, s + n); + + if (pResult != mpBegin) + return (size_type)((pResult - 1) - mpBegin); + } + return npos; + } + + EA_CONSTEXPR size_type find_last_of(const T* s, size_type pos = npos) const + { + return find_last_of(s, pos, (size_type)CharStrlen(s)); + } + + EA_CONSTEXPR size_type find_first_not_of(basic_string_view sw, size_type pos = 0) const EA_NOEXCEPT + { + return find_first_not_of(sw.mpBegin, pos, sw.mnCount); + } + + EA_CPP14_CONSTEXPR size_type find_first_not_of(T c, size_type pos = 0) const EA_NOEXCEPT + { + if (EASTL_LIKELY(pos <= mnCount)) + { + const auto pEnd = mpBegin + mnCount; + // Todo: Possibly make a specialized version of CharTypeStringFindFirstNotOf(pBegin, pEnd, c). + const const_iterator pResult = CharTypeStringFindFirstNotOf(mpBegin + pos, pEnd, &c, &c + 1); + + if (pResult != pEnd) + return (size_type)(pResult - mpBegin); + } + return npos; + } + + EA_CPP14_CONSTEXPR size_type find_first_not_of(const T* s, size_type pos, size_type n) const + { + if (EASTL_LIKELY(pos <= mnCount)) + { + const auto pEnd = mpBegin + mnCount; + const const_iterator pResult = CharTypeStringFindFirstNotOf(mpBegin + pos, pEnd, s, s + n); + + if (pResult != pEnd) + return (size_type)(pResult - mpBegin); + } + return npos; + } + + EA_CONSTEXPR size_type find_first_not_of(const T* s, size_type pos = 0) const + { + return find_first_not_of(s, pos, (size_type)CharStrlen(s)); + } + + EA_CONSTEXPR size_type find_last_not_of(basic_string_view sw, size_type pos = npos) const EA_NOEXCEPT + { + return find_last_not_of(sw.mpBegin, pos, sw.mnCount); + } + + EA_CPP14_CONSTEXPR size_type find_last_not_of(T c, size_type pos = npos) const EA_NOEXCEPT + { + if (EASTL_LIKELY(mnCount)) + { + // Todo: Possibly make a specialized version of CharTypeStringRFindFirstNotOf(pBegin, pEnd, c). + const value_type* const pEnd = mpBegin + eastl::min_alt(mnCount - 1, pos) + 1; + const value_type* const pResult = CharTypeStringRFindFirstNotOf(pEnd, mpBegin, &c, &c + 1); + + if (pResult != mpBegin) + return (size_type)((pResult - 1) - mpBegin); + } + return npos; + } + + EA_CPP14_CONSTEXPR size_type find_last_not_of(const T* s, size_type pos, size_type n) const + { + if (EASTL_LIKELY(mnCount)) + { + const value_type* const pEnd = mpBegin + eastl::min_alt(mnCount - 1, pos) + 1; + const value_type* const pResult = CharTypeStringRFindFirstNotOf(pEnd, mpBegin, s, s + n); + + if (pResult != mpBegin) + return (size_type)((pResult - 1) - mpBegin); + } + return npos; + } + + EA_CONSTEXPR size_type find_last_not_of(const T* s, size_type pos = npos) const + { + return find_last_not_of(s, pos, (size_type)CharStrlen(s)); + } + }; + + + // global operators + template + inline EA_CONSTEXPR bool operator==(basic_string_view lhs, basic_string_view rhs) + { + return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0); + } + + template + inline EA_CONSTEXPR bool operator!=(basic_string_view lhs, basic_string_view rhs) + { + return !(lhs == rhs); + } + + template + inline EA_CONSTEXPR bool operator<(basic_string_view lhs, basic_string_view rhs) + { + return lhs.compare(rhs) < 0; + } + + template + inline EA_CONSTEXPR bool operator<=(basic_string_view lhs, basic_string_view rhs) + { + return !(rhs < lhs); + } + + template + inline EA_CONSTEXPR bool operator>(basic_string_view lhs, basic_string_view rhs) + { + return rhs < lhs; + } + + template + inline EA_CONSTEXPR bool operator>=(basic_string_view lhs, basic_string_view rhs) + { + return !(lhs < rhs); + } + + // string_view / wstring_view + typedef basic_string_view string_view; + typedef basic_string_view wstring_view; + + // C++17 string types + typedef basic_string_view u8string_view; // Actually not a C++17 type, but added for consistency. + typedef basic_string_view u16string_view; + typedef basic_string_view u32string_view; + + + /// hash + /// + /// We provide EASTL hash function objects for use in hash table containers. + /// + /// Example usage: + /// #include + /// hash_set stringHashSet; + /// + template struct hash; + + template<> struct hash + { + size_t operator()(const string_view& x) const + { + const unsigned char* p = (const unsigned char*)x.data(); // To consider: limit p to at most 256 chars. + unsigned int c, result = 2166136261U; // We implement an FNV-like string hash. + while((c = *p++) != 0) // Using '!=' disables compiler warnings. + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template<> struct hash + { + size_t operator()(const u16string_view& x) const + { + const char16_t* p = x.data(); + unsigned int c, result = 2166136261U; + while((c = *p++) != 0) + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template<> struct hash + { + size_t operator()(const u32string_view& x) const + { + const char32_t* p = x.data(); + unsigned int c, result = 2166136261U; + while((c = (unsigned int)*p++) != 0) + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + template<> struct hash + { + size_t operator()(const wstring_view& x) const + { + const wchar_t* p = x.data(); + unsigned int c, result = 2166136261U; + while((c = (unsigned int)*p++) != 0) + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + #endif + + + #if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED + inline namespace literals + { + inline namespace string_view_literals + { + EA_CONSTEXPR string_view operator"" sv(const char* str, size_t len) EA_NOEXCEPT { return {str, len}; } + EA_CONSTEXPR u16string_view operator"" sv(const char16_t* str, size_t len) EA_NOEXCEPT { return {str, len}; } + EA_CONSTEXPR u32string_view operator"" sv(const char32_t* str, size_t len) EA_NOEXCEPT { return {str, len}; } + EA_CONSTEXPR wstring_view operator"" sv(const wchar_t* str, size_t len) EA_NOEXCEPT { return {str, len}; } + } + } + #endif + +} // namespace eastl + +EA_RESTORE_VC_WARNING() +#endif // EASTL_STRING_VIEW_H diff --git a/test/packages/EABase/include/Common/EABase/eabase.h b/test/packages/EABase/include/Common/EABase/eabase.h index 034ac3d2..161abe7c 100644 --- a/test/packages/EABase/include/Common/EABase/eabase.h +++ b/test/packages/EABase/include/Common/EABase/eabase.h @@ -730,7 +730,11 @@ #endif #else typedef uint16_t char16_t; - typedef wchar_t char32_t; + #if defined(__cplusplus) + typedef wchar_t char32_t; + #else + typedef uint32_t char32_t; + #endif #endif #endif @@ -895,6 +899,8 @@ // static_assert is defined by the compiler. #elif defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401) && defined(EA_COMPILER_CPP11_ENABLED) // static_assert is defined by the compiler. +#elif !defined(__cplusplus) && defined(__GLIBC__) && defined(__USE_ISOC11) + // static_assert is defined by the compiler. #else #define NEED_CUSTOM_STATIC_ASSERT #endif diff --git a/test/source/EASTLTest.h b/test/source/EASTLTest.h index 4416f2c1..c18637bc 100644 --- a/test/source/EASTLTest.h +++ b/test/source/EASTLTest.h @@ -79,6 +79,8 @@ int TestRatio(); int TestChrono(); int TestOptional(); int TestAny(); +int TestCharTraits(); +int TestStringView(); // Now enable warnings as desired. diff --git a/test/source/TestCharTraits.cpp b/test/source/TestCharTraits.cpp new file mode 100644 index 00000000..bbcab54f --- /dev/null +++ b/test/source/TestCharTraits.cpp @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#include "EASTLTest.h" +#include +#include + + +template +int TestCharTraits() +{ + int nErrorCount = 0; + return nErrorCount; +} + + +int TestCharTraits() +{ + using namespace eastl; + + int nErrorCount = 0; + + nErrorCount += TestCharTraits(); + nErrorCount += TestCharTraits(); + nErrorCount += TestCharTraits(); + nErrorCount += TestCharTraits(); + + return nErrorCount; +} + + + + + + + + + diff --git a/test/source/TestFunctional.cpp b/test/source/TestFunctional.cpp index f3d4580d..cbb3fda8 100644 --- a/test/source/TestFunctional.cpp +++ b/test/source/TestFunctional.cpp @@ -390,9 +390,9 @@ int TestFunctional() nErrorCount += TestHashHelper('E'); nErrorCount += TestHashHelper(0xEAEA); nErrorCount += TestHashHelper(0x00EA4330); - #if !defined(EA_WCHAR_T_NON_NATIVE) - nErrorCount += TestHashHelper(L'E'); - #endif + #if !defined(EA_WCHAR_T_NON_NATIVE) + nErrorCount += TestHashHelper(L'E'); + #endif nErrorCount += TestHashHelper(4330); nErrorCount += TestHashHelper(4330u); nErrorCount += TestHashHelper(4330); diff --git a/test/source/TestOptional.cpp b/test/source/TestOptional.cpp index a335134a..7ffbfad2 100644 --- a/test/source/TestOptional.cpp +++ b/test/source/TestOptional.cpp @@ -79,6 +79,11 @@ int TestOptional() VERIFY(static_cast(o)); VERIFY(o.value_or(0x8BADF00D) == 1024); VERIFY(o.value() == 1024); + + // Test reset + o.reset(); + VERIFY(!o); + VERIFY(o.value_or(0x8BADF00D) == (int)0x8BADF00D); } { diff --git a/test/source/TestString.cpp b/test/source/TestString.cpp index 2a410818..245376bf 100644 --- a/test/source/TestString.cpp +++ b/test/source/TestString.cpp @@ -11,8 +11,7 @@ using namespace eastl; -// todo: comment on this mess being required inorder to inject string literal string conversion macros into the unit -// test code. +// this mess is required inorder to inject string literal string conversion macros into the unit tests #define TEST_STRING_NAME TestBasicString #define LITERAL(x) x #include "TestString.inl" diff --git a/test/source/TestStringView.cpp b/test/source/TestStringView.cpp new file mode 100644 index 00000000..566c4173 --- /dev/null +++ b/test/source/TestStringView.cpp @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#include "EASTLTest.h" +#include +#include +#include + + +// this mess is required inorder to inject string literal string conversion macros into the unit tests +#define TEST_STRING_NAME TestBasicStringView +#define LITERAL(x) x +#include "TestStringView.inl" + +#define TEST_STRING_NAME TestBasicStringViewW +#define LITERAL(x) EA_WCHAR(x) +#include "TestStringView.inl" + +#define TEST_STRING_NAME TestBasicStringView16 +#define LITERAL(x) EA_CHAR16(x) +#include "TestStringView.inl" + +#define TEST_STRING_NAME TestBasicStringView32 +#define LITERAL(x) EA_CHAR32(x) +#include "TestStringView.inl" + + +int TestStringView() +{ + using namespace eastl; + int nErrorCount = 0; + + nErrorCount += TestBasicStringView>(); + nErrorCount += TestBasicStringView(); + + nErrorCount += TestBasicStringViewW>(); + nErrorCount += TestBasicStringViewW(); + + nErrorCount += TestBasicStringView16>(); + nErrorCount += TestBasicStringView16(); + +#if EA_CHAR32_NATIVE + nErrorCount += TestBasicStringView32>(); + nErrorCount += TestBasicStringView32(); +#endif + + return nErrorCount; +} + diff --git a/test/source/TestStringView.inl b/test/source/TestStringView.inl new file mode 100644 index 00000000..e9d9b316 --- /dev/null +++ b/test/source/TestStringView.inl @@ -0,0 +1,432 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +template +int TEST_STRING_NAME() +{ + int nErrorCount = 0; + { + // EA_CONSTEXPR basic_string_view() + { + StringViewT sw; + VERIFY(sw.empty()); + VERIFY(sw.data() == nullptr); + VERIFY(sw.size() == 0); + VERIFY(sw.size() == sw.length()); + } + + // EA_CONSTEXPR basic_string_view(const basic_string_view& other) = default; + { + auto* pLiteral = LITERAL("Hello, World"); + StringViewT sw1(pLiteral); + StringViewT sw2(sw1); + VERIFY(sw1.size() == sw2.size()); + VERIFY(eastl::Compare(sw1.data(), sw2.data(), sw1.size()) == 0); + } + + // EA_CONSTEXPR basic_string_view(const T* s, size_type count) + { + { + StringViewT sw(LITERAL("Hello, World"), 12); + VERIFY(!sw.empty()); + VERIFY(sw.data() != nullptr); + VERIFY(sw.size() == 12); + VERIFY(sw.size() == sw.length()); + } + + { + StringViewT sw(LITERAL("Hello, World"), 5); + VERIFY(!sw.empty()); + VERIFY(sw.data() != nullptr); + VERIFY(sw.size() == 5); + VERIFY(sw.size() == sw.length()); + VERIFY(eastl::Compare(sw.data(), LITERAL("Hello"), sw.size()) == 0); + } + } + + // EA_CONSTEXPR basic_string_view(const T* s) + { + auto* pLiteral = LITERAL("Vancouver, Canada"); + StringViewT sw(pLiteral); + VERIFY(!sw.empty()); + VERIFY(sw.data() != nullptr); + VERIFY(sw.size() == 17); + VERIFY(sw.size() == sw.length()); + VERIFY(eastl::Compare(sw.data(), pLiteral, sw.size()) == 0); + } + + // basic_string_view& operator=(const basic_string_view& view) = default; + { + auto* pLiteral = LITERAL("Hello, World"); + StringViewT sw1(pLiteral); + StringViewT sw2; + VERIFY(!sw1.empty()); + VERIFY(sw2.empty()); + + sw2 = sw1; + + VERIFY(!sw1.empty()); + VERIFY(!sw2.empty()); + VERIFY(sw1.size() == sw2.size()); + VERIFY(eastl::Compare(sw1.data(), pLiteral, sw1.size()) == 0); + VERIFY(eastl::Compare(sw2.data(), pLiteral, sw2.size()) == 0); + } + + // EA_CONSTEXPR const_iterator begin() const EA_NOEXCEPT + // EA_CONSTEXPR const_iterator cbegin() const EA_NOEXCEPT + // EA_CONSTEXPR const_iterator end() const EA_NOEXCEPT + // EA_CONSTEXPR const_iterator cend() const EA_NOEXCEPT + // EA_CONSTEXPR const_reverse_iterator rbegin() const EA_NOEXCEPT + // EA_CONSTEXPR const_reverse_iterator crbegin() const EA_NOEXCEPT + // EA_CONSTEXPR const_reverse_iterator rend() const EA_NOEXCEPT + // EA_CONSTEXPR const_reverse_iterator crend() const EA_NOEXCEPT + { + // TODO(rparolin): implement me + } + + // EA_CONSTEXPR const_pointer data() const + { + auto* pLiteral = LITERAL("Vancouver, Canada"); + StringViewT sw(pLiteral); + VERIFY(sw.data() != nullptr); + VERIFY(eastl::Compare(sw.data(), pLiteral, sw.size()) == 0); + VERIFY(eastl::Compare(sw.data() + 11, LITERAL("Canada"), 6) == 0); + } + + // EA_CONSTEXPR const_reference front() const + // EA_CONSTEXPR const_reference back() const + { + { + StringViewT sw(LITERAL("Vancouver, Canada")); + VERIFY(sw.front() == LITERAL('V')); + VERIFY(sw.back() == LITERAL('a')); + + } + { + StringViewT sw(LITERAL("Canada")); + VERIFY(sw.front() == LITERAL('C')); + VERIFY(sw.back() == LITERAL('a')); + } + } + + // EA_CONSTEXPR const_reference operator[](size_type pos) const + { + StringViewT sw(LITERAL("Vancouver")); + VERIFY(sw[0] == LITERAL('V')); + VERIFY(sw[1] == LITERAL('a')); + VERIFY(sw[2] == LITERAL('n')); + VERIFY(sw[3] == LITERAL('c')); + VERIFY(sw[4] == LITERAL('o')); + VERIFY(sw[5] == LITERAL('u')); + VERIFY(sw[6] == LITERAL('v')); + VERIFY(sw[7] == LITERAL('e')); + VERIFY(sw[8] == LITERAL('r')); + } + + // EA_CONSTEXPR size_type size() const EA_NOEXCEPT + // EA_CONSTEXPR size_type length() const EA_NOEXCEPT + // EA_CONSTEXPR size_type max_size() const EA_NOEXCEPT + // EA_CONSTEXPR bool empty() const EA_NOEXCEPT + { + StringViewT sw(LITERAL("http://en.cppreference.com/w/cpp/header/string_view")); + VERIFY(sw.size() == 51); + VERIFY(sw.length() == 51); + VERIFY(sw.max_size() == eastl::numeric_limits::max()); + VERIFY(!sw.empty()); + } + + // EA_CONSTEXPR void swap(basic_string_view& v) + { + auto* pV = LITERAL("Vancouver"); + auto* pC = LITERAL("Canada"); + StringViewT sw1(pV); + StringViewT sw2(pC); + sw1.swap(sw2); + VERIFY(eastl::Compare(sw1.data(), pC, sw1.size()) == 0); + VERIFY(eastl::Compare(sw2.data(), pV, sw2.size()) == 0); + } + + // EA_CONSTEXPR void remove_prefix(size_type n) + // EA_CONSTEXPR void remove_suffix(size_type n) + { + StringViewT sw(LITERAL("Vancouver")); + sw.remove_prefix(3); + VERIFY(eastl::Compare(sw.data(), LITERAL("couver"), sw.size()) == 0); + VERIFY(sw.size() == 6); + + sw.remove_prefix(3); + VERIFY(eastl::Compare(sw.data(), LITERAL("ver"), sw.size()) == 0); + VERIFY(sw.size() == 3); + + sw.remove_suffix(1); + VERIFY(eastl::Compare(sw.data(), LITERAL("ve"), sw.size()) == 0); + VERIFY(sw.size() == 2); + + sw.remove_suffix(1); + VERIFY(eastl::Compare(sw.data(), LITERAL("v"), sw.size()) == 0); + VERIFY(sw.size() == 1); + + sw.remove_suffix(1); + VERIFY(eastl::Compare(sw.data(), LITERAL(""), sw.size()) == 0); + VERIFY(sw.size() == 0); + } + + // size_type copy(T* s, size_type n, size_type pos = 0) const; + { + typename StringViewT::value_type buf[256]; + StringViewT sw(LITERAL("**Hello, World")); + auto cnt = sw.copy(buf, 5, 2); + VERIFY(eastl::Compare(buf, LITERAL("Hello"), 5) == 0); + VERIFY(cnt == 5); + } + + // EA_CONSTEXPR basic_string_view substr(size_type pos = 0, size_type n = npos) const; + { + StringViewT sw(LITERAL("**Hello, World")); + auto sw2 = sw.substr(2, 5); + VERIFY(eastl::Compare(sw2.data(), LITERAL("Hello"), sw2.size()) == 0); + } + + // EA_CONSTEXPR int compare(basic_string_view s) const EA_NOEXCEPT; + { + { + VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("A"))) == 0); + VERIFY(StringViewT(LITERAL("a")).compare(StringViewT(LITERAL("a"))) == 0); + VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("a"))) != 0); + VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("a"))) < 0); + VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("A"))) <= 0); + VERIFY(StringViewT(LITERAL("a")).compare(StringViewT(LITERAL("A"))) > 0); + VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("A"))) >= 0); + } + + { + StringViewT sw1(LITERAL("Hello, World")); + StringViewT sw2(LITERAL("Hello, WWorld")); + StringViewT sw3(LITERAL("Hello, Wzorld")); + VERIFY(sw1.compare(sw1) == 0); + VERIFY(sw1.compare(sw2) > 0); + VERIFY(sw1.compare(sw3) < 0); + } + } + + // EA_CONSTEXPR int compare(size_type pos1, size_type n1, basic_string_view s) const; + { + StringViewT sw1(LITERAL("*** Hello ***")); + StringViewT sw2(LITERAL("Hello")); + VERIFY(sw1.compare(4, 5, sw2) == 0); + } + + // EA_CONSTEXPR int compare(size_type pos1, size_type n1, basic_string_view s, size_type pos2, size_type n2) const; + { + StringViewT sw(LITERAL("Vancouver")); + VERIFY(sw.compare(0, 3, StringViewT(LITERAL("Van")), 0, 3) == 0); + VERIFY(sw.compare(6, 3, StringViewT(LITERAL("ver")), 0, 3) == 0); + VERIFY(sw.compare(0, 3, StringViewT(LITERAL("Tan")), 0, 3) != 0); + } + + // EA_CONSTEXPR int compare(const T* s) const; + { + StringViewT sw(LITERAL("Hello")); + VERIFY(sw.compare(LITERAL("Vancouver")) != 0); + VERIFY(sw.compare(LITERAL("Vancouver!")) != 0); + VERIFY(sw.compare(LITERAL("Hello")) == 0); + } + + // EA_CONSTEXPR int compare(size_type pos1, size_type n1, const T* s) const; + { + StringViewT sw(LITERAL("*** Hello")); + VERIFY(sw.compare(4, 5, LITERAL("Hello")) == 0); + VERIFY(sw.compare(4, 5, LITERAL("Hello 555")) == 0); + VERIFY(sw.compare(4, 5, LITERAL("hello")) != 0); + } + + // EA_CONSTEXPR int compare(size_type pos1, size_type n1, const T* s, size_type n2) const; + { + StringViewT sw(LITERAL("*** Hello ***")); + VERIFY(sw.compare(4, 5, LITERAL("Hello"), 5) == 0); + VERIFY(sw.compare(0, 1, LITERAL("*"), 1) == 0); + VERIFY(sw.compare(0, 2, LITERAL("**"), 1) == 0); + VERIFY(sw.compare(0, 2, LITERAL("**"), 2) == 0); + VERIFY(sw.compare(0, 2, LITERAL("^^"), 2) != 0); + } + + + // EA_CONSTEXPR size_type find(basic_string_view s, size_type pos = 0) const EA_NOEXCEPT; + { + StringViewT sw(LITERAL("*** Hello ***")); + VERIFY(sw.find(StringViewT(LITERAL("Hello"))) != StringViewT::npos); + VERIFY(sw.find(StringViewT(LITERAL("ell"))) != StringViewT::npos); + VERIFY(sw.find(StringViewT(LITERAL("FailToFindMe"))) == StringViewT::npos); + } + + // EA_CONSTEXPR size_type find(T c, size_type pos = 0) const EA_NOEXCEPT; + { + StringViewT sw(LITERAL("*** Hello ***")); + VERIFY(sw.find(LITERAL("H")) == 4); + VERIFY(sw.find(LITERAL("e")) == 5); + VERIFY(sw.find(LITERAL("l")) == 6); + VERIFY(sw.find(LITERAL("o")) == 8); + VERIFY(sw.find(LITERAL("&")) == StringViewT::npos); + VERIFY(sw.find(LITERAL("@")) == StringViewT::npos); + } + + // EA_CONSTEXPR size_type find(const T* s, size_type pos, size_type n) const; + { + StringViewT sw(LITERAL("Hello, Vancouver")); + VERIFY(sw.find(LITERAL("Hello"), 0, 3) != StringViewT::npos); + VERIFY(sw.find(LITERAL("Hello"), 3, 3) == StringViewT::npos); + VERIFY(sw.find(LITERAL("Vancouv"), 7, 7) != StringViewT::npos); + } + + // EA_CONSTEXPR size_type find(const T* s, size_type pos = 0) const; + { + StringViewT sw(LITERAL("Hello, Vancouver")); + VERIFY(sw.find(LITERAL("Hello"), 0) != StringViewT::npos); + VERIFY(sw.find(LITERAL("Hello"), 3) == StringViewT::npos); + VERIFY(sw.find(LITERAL("Vancouv"), 7) != StringViewT::npos); + } + + + // EA_CONSTEXPR size_type rfind(basic_string_view s, size_type pos = npos) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type rfind(T c, size_type pos = npos) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type rfind(const T* s, size_type pos, size_type n) const; + // EA_CONSTEXPR size_type rfind(const T* s, size_type pos = npos) const; + { + StringViewT str(LITERAL("abcdefghijklmnopqrstuvwxyz")); + + VERIFY(str.find(StringViewT(LITERAL("d"))) != StringViewT::npos); + VERIFY(str.find(StringViewT(LITERAL("tuv"))) != StringViewT::npos); + VERIFY(str.find(StringViewT(LITERAL("123r"))) == StringViewT::npos); + + VERIFY(str.find(LITERAL("d")) != StringViewT::npos); + VERIFY(str.find(LITERAL("tuv")) != StringViewT::npos); + VERIFY(str.find(LITERAL("123r")) == StringViewT::npos); + + VERIFY(str.find(LITERAL("d"), 0) != StringViewT::npos); + VERIFY(str.find(LITERAL("tuv"), 2) != StringViewT::npos); + VERIFY(str.find(LITERAL("123r"), 2) == StringViewT::npos); + + VERIFY(str.find(LITERAL('d'), 0) != StringViewT::npos); + VERIFY(str.find(LITERAL('t'), 2) != StringViewT::npos); + VERIFY(str.find(LITERAL('1'), 2) == StringViewT::npos); + } + + // EA_CONSTEXPR size_type find_first_of(basic_string_view s, size_type pos = 0) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type find_first_of(T c, size_type pos = 0) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type find_first_of(const T* s, size_type pos, size_type n) const; + // EA_CONSTEXPR size_type find_first_of(const T* s, size_type pos = 0) const; + { + StringViewT str(LITERAL("aaaaabbbbbcccdddddeeeeefffggh")); + + VERIFY(str.find_first_of(StringViewT(LITERAL("aaa"))) == 0); + VERIFY(str.find_first_of(LITERAL("aab")) == 0); + VERIFY(str.find_first_of(LITERAL("baab")) == 0); + VERIFY(str.find_first_of(LITERAL("ceg")) == 10); + VERIFY(str.find_first_of(LITERAL("eeef"), 1, 2) == 18); + VERIFY(str.find_first_of(LITERAL("eeef"), 1, 4) == 18); + VERIFY(str.find_first_of(LITERAL('g')) == 26); + VERIFY(str.find_first_of(LITERAL('$')) == StringViewT::npos); + } + + // EA_CONSTEXPR size_type find_last_of(basic_string_view s, size_type pos = npos) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type find_last_of(T c, size_type pos = npos) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type find_last_of(const T* s, size_type pos, size_type n) const; + // EA_CONSTEXPR size_type find_last_of(const T* s, size_type pos = npos) const; + { + StringViewT str(LITERAL("aaaaabbbbbcccdddddeeeeefffggh")); + + VERIFY(str.find_last_of(StringViewT(LITERAL("aaa"))) == 4); + VERIFY(str.find_last_of(LITERAL("aab")) == 9); + VERIFY(str.find_last_of(LITERAL("baab")) == 9); + VERIFY(str.find_last_of(LITERAL("ceg")) == 27); + // VERIFY(str.find_last_of(LITERAL("eeef"), 1, 2) == StringViewT::npos); // todo: FIX ME + // VERIFY(str.find_last_of(LITERAL("eeef"), 1, 4) == StringViewT::npos); // todo: FIX ME + VERIFY(str.find_last_of(LITERAL('g')) == 27); + VERIFY(str.find_last_of(LITERAL('$')) == StringViewT::npos); + } + + // EA_CONSTEXPR size_type find_first_not_of(basic_string_view s, size_type pos = 0) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type find_first_not_of(T c, size_type pos = 0) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type find_first_not_of(const T* s, size_type pos, size_type n) const; + // EA_CONSTEXPR size_type find_first_not_of(const T* s, size_type pos = 0) const; + { + StringViewT str(LITERAL("aaaaabbbbbcccdddddeeeeefffggh")); + + VERIFY(str.find_first_not_of(StringViewT(LITERAL("abcdfg"))) == 18); + VERIFY(str.find_first_not_of(LITERAL("abcdfg")) == 18); + // VERIFY(str.find_first_not_of(LITERAL("abcdfg"), 2, 2) == 0); // todo: FIX ME + // VERIFY(str.find_first_not_of(LITERAL("abcdfg"), 0, 2) == 10); // todo: FIX ME + VERIFY(str.find_first_not_of(LITERAL('a')) == 5); + } + + + // EA_CONSTEXPR size_type find_last_not_of(basic_string_view s, size_type pos = npos) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type find_last_not_of(T c, size_type pos = npos) const EA_NOEXCEPT; + // EA_CONSTEXPR size_type find_last_not_of(const T* s, size_type pos, size_type n) const; + // EA_CONSTEXPR size_type find_last_not_of(const T* s, size_type pos = npos) const; + { + StringViewT str(LITERAL("aaaaabbbbbcccdddddeeeeefffggh")); + + VERIFY(str.find_last_not_of(StringViewT(LITERAL("a"))) == 28); + VERIFY(str.find_last_not_of(StringViewT(LITERAL("abcdfg"))) == 28); + VERIFY(str.find_last_not_of(StringViewT(LITERAL("abcdfgh"))) == 22); + VERIFY(str.find_last_not_of(LITERAL("abcdfgh")) == 22); + // VERIFY(str.find_last_not_of(LITERAL("abcdfg"), 2, 2) == 0); // todo: FIX ME + // VERIFY(str.find_last_not_of(LITERAL("abcdfg"), 0, 2) == 10); // todo: FIX ME + VERIFY(str.find_last_not_of(LITERAL('a')) == 28); + } + + // template + // constexpr bool operator==(basic_string_view lhs, basic_string_view rhs); + // template + // constexpr bool operator!=(basic_string_view lhs, basic_string_view rhs); + // template + // constexpr bool operator<(basic_string_view lhs, basic_string_view rhs); + // template + // constexpr bool operator<=(basic_string_view lhs, basic_string_view rhs); + // template + // constexpr bool operator>(basic_string_view lhs, basic_string_view rhs); + // template + // constexpr bool operator>=(basic_string_view lhs, basic_string_view rhs); + { + StringViewT sw1(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH")); + StringViewT sw2(LITERAL("aaaaabbbbbcccdddddeeeeefffggh")); + StringViewT sw3(LITERAL("0123456789!@#$%^&*()")); + + VERIFY(sw1 == StringViewT(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH"))); + VERIFY(sw1 != StringViewT(LITERAL("abcdefghijklmnopqrstuvwxyz"))); + VERIFY(sw1 < sw2); + VERIFY(sw1 <= sw2); + VERIFY(sw2 > sw1); + VERIFY(sw2 >= sw1); + } + + // constexpr string_view operator "" sv(const char* str, size_t len) noexcept; + // constexpr u16string_view operator "" sv(const char16_t* str, size_t len) noexcept; + // constexpr u32string_view operator "" sv(const char32_t* str, size_t len) noexcept; + // constexpr wstring_view operator "" sv(const wchar_t* str, size_t len) noexcept; + #if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED + { + static_assert(eastl::is_same_v, "string_view literal type mismatch"); + static_assert(eastl::is_same_v, "string_view literal type mismatch"); + static_assert(eastl::is_same_v, "string_view literal type mismatch"); + static_assert(eastl::is_same_v, "string_view literal type mismatch"); + } + #endif + + // template<> struct hash; + // template<> struct hash; + // template<> struct hash; + // template<> struct hash; + { + // todo + } + } + return nErrorCount; +} + +// Required to prevent manual undef of macros when 'TestString.inl' preprocessed at the top of the unit test cpp file. +#undef TEST_STRING_NAME +#undef LITERAL + diff --git a/test/source/TestVector.cpp b/test/source/TestVector.cpp index b9f5d296..24b9f8c6 100644 --- a/test/source/TestVector.cpp +++ b/test/source/TestVector.cpp @@ -1516,48 +1516,48 @@ int TestVector() eastl::vector v2(ci.begin(), ci.end()); } - -#if EASTL_MOVE_SEMANTICS_ENABLED - // unique_ptr tests - { - // Simple move-assignment test to prevent regressions where eastl::vector utilizes operations on T that are not necessary. + // If the legacy code path is enabled we cannot handle non-copyable types + #ifndef EASTL_VECTOR_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR + // unique_ptr tests { - eastl::vector> v1; - eastl::vector> v2; - v2 = eastl::move(v1); - } - - { - // This test verifies that eastl::vector can handle the move-assignment case where its utilizes two - // different allocator instances that do not compare equal. An example of an allocator that compares equal - // but isn't the same object instance is an allocator that shares the same memory allocation mechanism (eg. - // malloc). The memory allocated from one instance can be freed by another instance in the case where - // allocators compare equal. This test is verifying functionality in the opposite case where allocators - // instances do not compare equal and must clean up its own allocated memory. - InstanceAllocator::reset_all(); + // Simple move-assignment test to prevent regressions where eastl::vector utilizes operations on T that are not necessary. { - InstanceAllocator a1(uint8_t(0)), a2(uint8_t(1)); - eastl::vector, InstanceAllocator> v1(a1); - eastl::vector, InstanceAllocator> v2(a2); - - VERIFY(v1.get_allocator() != v2.get_allocator()); - - // add some data in the vector so we can move it to the other vector. - v1.push_back(nullptr); - v1.push_back(nullptr); - v1.push_back(nullptr); - v1.push_back(nullptr); - - VERIFY(!v1.empty() && v2.empty()); + eastl::vector> v1; + eastl::vector> v2; v2 = eastl::move(v1); - VERIFY(v1.empty() && !v2.empty()); - v1.swap(v2); - VERIFY(!v1.empty() && v2.empty()); } - VERIFY(InstanceAllocator::mMismatchCount == 0); + + { + // This test verifies that eastl::vector can handle the move-assignment case where its utilizes two + // different allocator instances that do not compare equal. An example of an allocator that compares equal + // but isn't the same object instance is an allocator that shares the same memory allocation mechanism (eg. + // malloc). The memory allocated from one instance can be freed by another instance in the case where + // allocators compare equal. This test is verifying functionality in the opposite case where allocators + // instances do not compare equal and must clean up its own allocated memory. + InstanceAllocator::reset_all(); + { + InstanceAllocator a1(uint8_t(0)), a2(uint8_t(1)); + eastl::vector, InstanceAllocator> v1(a1); + eastl::vector, InstanceAllocator> v2(a2); + + VERIFY(v1.get_allocator() != v2.get_allocator()); + + // add some data in the vector so we can move it to the other vector. + v1.push_back(nullptr); + v1.push_back(nullptr); + v1.push_back(nullptr); + v1.push_back(nullptr); + + VERIFY(!v1.empty() && v2.empty()); + v2 = eastl::move(v1); + VERIFY(v1.empty() && !v2.empty()); + v1.swap(v2); + VERIFY(!v1.empty() && v2.empty()); + } + VERIFY(InstanceAllocator::mMismatchCount == 0); + } } - } -#endif + #endif return nErrorCount; } diff --git a/test/source/main.cpp b/test/source/main.cpp index fb9bd9a9..f8d766d3 100644 --- a/test/source/main.cpp +++ b/test/source/main.cpp @@ -83,6 +83,8 @@ int EAMain(int argc, char* argv[]) TestApplication testSuite("EASTL Unit Tests", argc, argv); + testSuite.AddTest("StringView", TestStringView); + testSuite.AddTest("CharTraits", TestCharTraits); testSuite.AddTest("Any", TestAny); testSuite.AddTest("Optional", TestOptional); testSuite.AddTest("TypeTraits", TestTypeTraits);