diff options
Diffstat (limited to 'include/EASTL/string.h')
-rw-r--r-- | include/EASTL/string.h | 4296 |
1 files changed, 0 insertions, 4296 deletions
diff --git a/include/EASTL/string.h b/include/EASTL/string.h deleted file mode 100644 index 3a70b79..0000000 --- a/include/EASTL/string.h +++ /dev/null @@ -1,4296 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Implements a basic_string class, much like the C++ std::basic_string. -// The primary distinctions between basic_string and std::basic_string are: -// - basic_string has a few extension functions that allow for increased performance. -// - basic_string has a few extension functions that make use easier, -// such as a member sprintf function and member tolower/toupper functions. -// - basic_string supports debug memory naming natively. -// - basic_string is easier to read, debug, and visualize. -// - basic_string internally manually expands basic functions such as begin(), -// size(), etc. in order to improve debug performance and optimizer success. -// - basic_string is savvy to an environment that doesn't have exception handling, -// as is sometimes the case with console or embedded environments. -// - basic_string has less deeply nested function calls and allows the user to -// enable forced inlining in debug builds in order to reduce bloat. -// - basic_string doesn't use char traits. As a result, EASTL assumes that -// strings will hold characters and not exotic things like widgets. At the -// very least, basic_string assumes that the value_type is a POD. -// - basic_string::size_type is defined as eastl_size_t instead of size_t in -// order to save memory and run faster on 64 bit systems. -// - basic_string data is guaranteed to be contiguous. -// - basic_string data is guaranteed to be 0-terminated, and the c_str() function -// is guaranteed to return the same pointer as the data() which is guaranteed -// to be the same value as &string[0]. -// - basic_string has a set_capacity() function which frees excess capacity. -// The only way to do this with std::basic_string is via the cryptic non-obvious -// trick of using: basic_string<char>(x).swap(x); -// - basic_string has a force_size() function, which unilaterally moves the string -// end position (mpEnd) to the given location. Useful for when the user writes -// into the string via some external means such as C strcpy or sprintf. -// - basic_string substr() deviates from the standard and returns a string with -// a copy of this->get_allocator() -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Copy on Write (cow) -// -// This string implementation does not do copy on write (cow). This is by design, -// as cow penalizes 95% of string uses for the benefit of only 5% of the uses -// (these percentages are qualitative, not quantitative). The primary benefit of -// cow is that it allows for the sharing of string data between two string objects. -// Thus if you say this: -// string a("hello"); -// string b(a); -// the "hello" will be shared between a and b. If you then say this: -// a = "world"; -// then a will release its reference to "hello" and leave b with the only reference -// to it. Normally this functionality is accomplished via reference counting and -// with atomic operations or mutexes. -// -// The C++ standard does not say anything about basic_string and cow. However, -// for a basic_string implementation to be standards-conforming, a number of -// issues arise which dictate some things about how one would have to implement -// a cow string. The discussion of these issues will not be rehashed here, as you -// can read the references below for better detail than can be provided in the -// space we have here. However, we can say that the C++ standard is sensible and -// that anything we try to do here to allow for an efficient cow implementation -// would result in a generally unacceptable string interface. -// -// The disadvantages of cow strings are: -// - A reference count needs to exist with the string, which increases string memory usage. -// - With thread safety, atomic operations and mutex locks are expensive, especially -// on weaker memory systems such as console gaming platforms. -// - All non-const string accessor functions need to do a sharing check then the -// first such check needs to detach the string. Similarly, all string assignments -// need to do a sharing check as well. If you access the string before doing an -// assignment, the assignment doesn't result in a shared string, because the string -// has already been detached. -// - String sharing doesn't happen the large majority of the time. In some cases, -// the total sum of the reference count memory can exceed any memory savings -// gained by the strings that share representations. -// -// The addition of a string_cow class is under consideration for this library. -// There are conceivably some systems which have string usage patterns which would -// benefit from cow sharing. Such functionality is best saved for a separate string -// implementation so that the other string uses aren't penalized. -// -// References: -// This is a good starting HTML reference on the topic: -// http://www.gotw.ca/publications/optimizations.htm -// Here is a Usenet discussion on the topic: -// http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_thread/thread/3dc6af5198d0bf7/886c8642cb06e03d -// -/////////////////////////////////////////////////////////////////////////////// - - -#ifndef EASTL_STRING_H -#define EASTL_STRING_H - -#include <EASTL/internal/config.h> -#include <EASTL/allocator.h> -#include <EASTL/iterator.h> -#include <EASTL/algorithm.h> -#include <EASTL/initializer_list.h> -#include <EASTL/bonus/compressed_pair.h> - -EA_DISABLE_ALL_VC_WARNINGS() -#include <stddef.h> // size_t, ptrdiff_t, etc. -#include <stdarg.h> // vararg functionality. - -#include <stdlib.h> // malloc, free. -#include <stdio.h> // snprintf, etc. -#include <ctype.h> // toupper, etc. - -EA_DISABLE_GCC_WARNING(-Wtype-limits) -#include <wchar.h> -EA_RESTORE_GCC_WARNING() - -#include <string.h> // strlen, etc. - -#if EASTL_EXCEPTIONS_ENABLED - #include <stdexcept> // std::out_of_range, std::length_error. -#endif -EA_RESTORE_ALL_VC_WARNINGS() - - -// 4530 - C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc -// 4480 - nonstandard extension used: specifying underlying type for enum -// 4571 - catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. -// 4267 - 'argument' : conversion from 'size_t' to 'const uint32_t', possible loss of data. This is a bogus warning resulting from a bug in VC++. -// 4702 - unreachable code -EA_DISABLE_VC_WARNING(4530 4480 4571 4267 4702); - - -#if defined(EA_PRAGMA_ONCE_SUPPORTED) - #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/internal/char_traits.h> -#include <EASTL/string_view.h> - -/////////////////////////////////////////////////////////////////////////////// -// EASTL_STRING_EXPLICIT -// -// See EASTL_STRING_OPT_EXPLICIT_CTORS for documentation. -// -#if EASTL_STRING_OPT_EXPLICIT_CTORS - #define EASTL_STRING_EXPLICIT explicit -#else - #define EASTL_STRING_EXPLICIT -#endif -/////////////////////////////////////////////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////// -// Vsnprintf -// -// The user is expected to supply these functions one way or another. Note that -// these functions are expected to accept parameters as per the C99 standard. -// These functions can deal with C99 standard return values or Microsoft non-standard -// return values but act more efficiently if implemented via the C99 style. -// -// In the case of EASTL_EASTDC_VSNPRINTF == 1, the user is expected to either -// link EAStdC or provide the functions below that act the same. In the case of -// EASTL_EASTDC_VSNPRINTF == 0, the user is expected to provide the function -// implementations, and may simply use C vsnprintf if desired, though it's not -// completely portable between compilers. -// -#if EASTL_EASTDC_VSNPRINTF - namespace EA - { - namespace StdC - { - // Provided by the EAStdC package or by the user. - EASTL_EASTDC_API int Vsnprintf(char* EA_RESTRICT pDestination, size_t n, const char* EA_RESTRICT pFormat, va_list arguments); - EASTL_EASTDC_API int Vsnprintf(char16_t* EA_RESTRICT pDestination, size_t n, const char16_t* EA_RESTRICT pFormat, va_list arguments); - EASTL_EASTDC_API int Vsnprintf(char32_t* EA_RESTRICT pDestination, size_t n, const char32_t* EA_RESTRICT pFormat, va_list arguments); - #if EA_CHAR8_UNIQUE - EASTL_EASTDC_API int Vsnprintf(char8_t* EA_RESTRICT pDestination, size_t n, const char8_t* EA_RESTRICT pFormat, va_list arguments); - #endif - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - EASTL_EASTDC_API int Vsnprintf(wchar_t* EA_RESTRICT pDestination, size_t n, const wchar_t* EA_RESTRICT pFormat, va_list arguments); - #endif - } - } - - namespace eastl - { - inline int Vsnprintf(char* EA_RESTRICT pDestination, size_t n, const char* EA_RESTRICT pFormat, va_list arguments) - { return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments); } - - inline int Vsnprintf(char16_t* EA_RESTRICT pDestination, size_t n, const char16_t* EA_RESTRICT pFormat, va_list arguments) - { return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments); } - - inline int Vsnprintf(char32_t* EA_RESTRICT pDestination, size_t n, const char32_t* EA_RESTRICT pFormat, va_list arguments) - { return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments); } - - #if EA_CHAR8_UNIQUE - inline int Vsnprintf(char8_t* EA_RESTRICT pDestination, size_t n, const char8_t* EA_RESTRICT pFormat, va_list arguments) - { return EA::StdC::Vsnprintf((char*)pDestination, n, (const char*)pFormat, arguments); } - #endif - - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - inline int Vsnprintf(wchar_t* EA_RESTRICT pDestination, size_t n, const wchar_t* EA_RESTRICT pFormat, va_list arguments) - { return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments); } - #endif - } -#else - // User-provided functions. - extern int Vsnprintf8 (char* pDestination, size_t n, const char* pFormat, va_list arguments); - extern int Vsnprintf16(char16_t* pDestination, size_t n, const char16_t* pFormat, va_list arguments); - extern int Vsnprintf32(char32_t* pDestination, size_t n, const char32_t* pFormat, va_list arguments); - #if EA_CHAR8_UNIQUE - extern int Vsnprintf8 (char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments); - #endif - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - extern int VsnprintfW(wchar_t* pDestination, size_t n, const wchar_t* pFormat, va_list arguments); - #endif - - namespace eastl - { - inline int Vsnprintf(char* pDestination, size_t n, const char* pFormat, va_list arguments) - { return Vsnprintf8(pDestination, n, pFormat, arguments); } - - inline int Vsnprintf(char16_t* pDestination, size_t n, const char16_t* pFormat, va_list arguments) - { return Vsnprintf16(pDestination, n, pFormat, arguments); } - - inline int Vsnprintf(char32_t* pDestination, size_t n, const char32_t* pFormat, va_list arguments) - { return Vsnprintf32(pDestination, n, pFormat, arguments); } - - #if EA_CHAR8_UNIQUE - inline int Vsnprintf(char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments) - { return Vsnprintf8(pDestination, n, pFormat, arguments); } - #endif - - #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE - inline int Vsnprintf(wchar_t* pDestination, size_t n, const wchar_t* pFormat, va_list arguments) - { return VsnprintfW(pDestination, n, pFormat, arguments); } - #endif - } -#endif -/////////////////////////////////////////////////////////////////////////////// - - - -namespace eastl -{ - - /// EASTL_BASIC_STRING_DEFAULT_NAME - /// - /// Defines a default container name in the absence of a user-provided name. - /// - #ifndef EASTL_BASIC_STRING_DEFAULT_NAME - #define EASTL_BASIC_STRING_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " basic_string" // Unless the user overrides something, this is "EASTL basic_string". - #endif - - - /// EASTL_BASIC_STRING_DEFAULT_ALLOCATOR - /// - #ifndef EASTL_BASIC_STRING_DEFAULT_ALLOCATOR - #define EASTL_BASIC_STRING_DEFAULT_ALLOCATOR allocator_type(EASTL_BASIC_STRING_DEFAULT_NAME) - #endif - - - /////////////////////////////////////////////////////////////////////////////// - /// basic_string - /// - /// Implements a templated string class, somewhat like C++ std::basic_string. - /// - /// Notes: - /// As of this writing, an insert of a string into itself necessarily - /// triggers a reallocation, even if there is enough capacity in self - /// to handle the increase in size. This is due to the slightly tricky - /// nature of the operation of modifying one's self with one's self, - /// and thus the source and destination are being modified during the - /// operation. It might be useful to rectify this to the extent possible. - /// - /// Our usage of noexcept specifiers is a little different from the - /// requirements specified by std::basic_string in C++11. This is because - /// our allocators are instances and not types and thus can be non-equal - /// and result in exceptions during assignments that theoretically can't - /// occur with std containers. - /// - template <typename T, typename Allocator = EASTLAllocatorType> - class basic_string - { - public: - typedef basic_string<T, Allocator> this_type; - typedef basic_string_view<T> view_type; - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T* iterator; // Maintainer note: We want to leave iterator defined as T* -- at least in release builds -- as this gives some algorithms an advantage that optimizers cannot get around. - typedef const T* const_iterator; - typedef eastl::reverse_iterator<iterator> reverse_iterator; - typedef eastl::reverse_iterator<const_iterator> const_reverse_iterator; - typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. - typedef ptrdiff_t difference_type; - typedef Allocator allocator_type; - - static const EA_CONSTEXPR size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position. - - public: - // CtorDoNotInitialize exists so that we can create a constructor that allocates but doesn't - // initialize and also doesn't collide with any other constructor declaration. - struct CtorDoNotInitialize{}; - - // CtorSprintf exists so that we can create a constructor that accepts printf-style - // arguments but also doesn't collide with any other constructor declaration. - #ifdef EA_PLATFORM_MINGW - // Workaround for MinGW compiler bug: variadic arguments are corrupted if empty object is passed before it - struct CtorSprintf{ int dummy; }; - #else - struct CtorSprintf{}; - #endif - - // CtorConvert exists so that we can have a constructor that implements string encoding - // conversion, such as between UCS2 char16_t and UTF8 char8_t. - struct CtorConvert{}; - - protected: - // Masks used to determine if we are in SSO or Heap - #ifdef EA_SYSTEM_BIG_ENDIAN - // Big Endian use LSB, unless we want to reorder struct layouts on endianness, Bit is set when we are in Heap - static EA_CONSTEXPR_OR_CONST size_type kHeapMask = 0x1; - static EA_CONSTEXPR_OR_CONST size_type kSSOMask = 0x1; - #else - // Little Endian use MSB - static EA_CONSTEXPR_OR_CONST size_type kHeapMask = ~(size_type(~size_type(0)) >> 1); - static EA_CONSTEXPR_OR_CONST size_type kSSOMask = 0x80; - #endif - - public: - #ifdef EA_SYSTEM_BIG_ENDIAN - static EA_CONSTEXPR_OR_CONST size_type kMaxSize = (~kHeapMask) >> 1; - #else - static EA_CONSTEXPR_OR_CONST size_type kMaxSize = ~kHeapMask; - #endif - - protected: - // The view of memory when the string data is obtained from the allocator. - struct HeapLayout - { - value_type* mpBegin; // Begin of string. - size_type mnSize; // Size of the string. Number of characters currently in the string, not including the trailing '0' - size_type mnCapacity; // Capacity of the string. Number of characters string can hold, not including the trailing '0' - }; - - template <typename CharT, size_t = sizeof(CharT)> - struct SSOPadding - { - char padding[sizeof(CharT) - sizeof(char)]; - }; - - template <typename CharT> - struct SSOPadding<CharT, 1> - { - // template specialization to remove the padding structure to avoid warnings on zero length arrays - // also, this allows us to take advantage of the empty-base-class optimization. - }; - - // The view of memory when the string data is able to store the string data locally (without a heap allocation). - struct SSOLayout - { - static EA_CONSTEXPR_OR_CONST size_type SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type); - - // mnSize must correspond to the last byte of HeapLayout.mnCapacity, so we don't want the compiler to insert - // padding after mnSize if sizeof(value_type) != 1; Also ensures both layouts are the same size. - struct SSOSize : SSOPadding<value_type> - { - char mnRemainingSize; - }; - - value_type mData[SSO_CAPACITY]; // Local buffer for string data. - SSOSize mRemainingSizeField; - }; - - // This view of memory is a utility structure for easy copying of the string data. - struct RawLayout - { - char mBuffer[sizeof(HeapLayout)]; - }; - - static_assert(sizeof(SSOLayout) == sizeof(HeapLayout), "heap and sso layout structures must be the same size"); - static_assert(sizeof(HeapLayout) == sizeof(RawLayout), "heap and raw layout structures must be the same size"); - - // This implements the 'short string optimization' or SSO. SSO reuses the existing storage of string class to - // hold string data short enough to fit therefore avoiding a heap allocation. The number of characters stored in - // the string SSO buffer is variable and depends on the string character width. This implementation favors a - // consistent string size than increasing the size of the string local data to accommodate a consistent number - // of characters despite character width. - struct Layout - { - union - { - HeapLayout heap; - SSOLayout sso; - RawLayout raw; - }; - - Layout() { ResetToSSO(); } // start as SSO by default - Layout(const Layout& other) { Copy(*this, other); } - Layout(Layout&& other) { Move(*this, other); } - Layout& operator=(const Layout& other) { Copy(*this, other); return *this; } - Layout& operator=(Layout&& other) { Move(*this, other); return *this; } - - // We are using Heap when the bit is set, easier to conceptualize checking IsHeap instead of IsSSO - inline bool IsHeap() const EA_NOEXCEPT { return !!(sso.mRemainingSizeField.mnRemainingSize & kSSOMask); } - inline bool IsSSO() const EA_NOEXCEPT { return !IsHeap(); } - inline value_type* SSOBufferPtr() EA_NOEXCEPT { return sso.mData; } - inline const value_type* SSOBufferPtr() const EA_NOEXCEPT { return sso.mData; } - - // Largest value for SSO.mnSize == 23, which has two LSB bits set, but on big-endian (BE) - // use least significant bit (LSB) to denote heap so shift. - inline size_type GetSSOSize() const EA_NOEXCEPT - { - #ifdef EA_SYSTEM_BIG_ENDIAN - return SSOLayout::SSO_CAPACITY - (sso.mRemainingSizeField.mnRemainingSize >> 2); - #else - return (SSOLayout::SSO_CAPACITY - sso.mRemainingSizeField.mnRemainingSize); - #endif - } - inline size_type GetHeapSize() const EA_NOEXCEPT { return heap.mnSize; } - inline size_type GetSize() const EA_NOEXCEPT { return IsHeap() ? GetHeapSize() : GetSSOSize(); } - - inline void SetSSOSize(size_type size) EA_NOEXCEPT - { - #ifdef EA_SYSTEM_BIG_ENDIAN - sso.mRemainingSizeField.mnRemainingSize = (char)((SSOLayout::SSO_CAPACITY - size) << 2); - #else - sso.mRemainingSizeField.mnRemainingSize = (char)(SSOLayout::SSO_CAPACITY - size); - #endif - } - - inline void SetHeapSize(size_type size) EA_NOEXCEPT { heap.mnSize = size; } - inline void SetSize(size_type size) EA_NOEXCEPT { IsHeap() ? SetHeapSize(size) : SetSSOSize(size); } - - inline size_type GetRemainingCapacity() const EA_NOEXCEPT { return size_type(CapacityPtr() - EndPtr()); } - - inline value_type* HeapBeginPtr() EA_NOEXCEPT { return heap.mpBegin; }; - inline const value_type* HeapBeginPtr() const EA_NOEXCEPT { return heap.mpBegin; }; - - inline value_type* SSOBeginPtr() EA_NOEXCEPT { return sso.mData; } - inline const value_type* SSOBeginPtr() const EA_NOEXCEPT { return sso.mData; } - - inline value_type* BeginPtr() EA_NOEXCEPT { return IsHeap() ? HeapBeginPtr() : SSOBeginPtr(); } - inline const value_type* BeginPtr() const EA_NOEXCEPT { return IsHeap() ? HeapBeginPtr() : SSOBeginPtr(); } - - inline value_type* HeapEndPtr() EA_NOEXCEPT { return heap.mpBegin + heap.mnSize; } - inline const value_type* HeapEndPtr() const EA_NOEXCEPT { return heap.mpBegin + heap.mnSize; } - - inline value_type* SSOEndPtr() EA_NOEXCEPT { return sso.mData + GetSSOSize(); } - inline const value_type* SSOEndPtr() const EA_NOEXCEPT { return sso.mData + GetSSOSize(); } - - // Points to end of character stream, *ptr == '0' - inline value_type* EndPtr() EA_NOEXCEPT { return IsHeap() ? HeapEndPtr() : SSOEndPtr(); } - inline const value_type* EndPtr() const EA_NOEXCEPT { return IsHeap() ? HeapEndPtr() : SSOEndPtr(); } - - inline value_type* HeapCapacityPtr() EA_NOEXCEPT { return heap.mpBegin + GetHeapCapacity(); } - inline const value_type* HeapCapacityPtr() const EA_NOEXCEPT { return heap.mpBegin + GetHeapCapacity(); } - - inline value_type* SSOCapacityPtr() EA_NOEXCEPT { return sso.mData + SSOLayout::SSO_CAPACITY; } - inline const value_type* SSOCapacityPtr() const EA_NOEXCEPT { return sso.mData + SSOLayout::SSO_CAPACITY; } - - // Points to end of the buffer at the terminating '0', *ptr == '0' <- only true when size() == capacity() - inline value_type* CapacityPtr() EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapacityPtr(); } - inline const value_type* CapacityPtr() const EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapacityPtr(); } - - inline void SetHeapBeginPtr(value_type* pBegin) EA_NOEXCEPT { heap.mpBegin = pBegin; } - - inline void SetHeapCapacity(size_type cap) EA_NOEXCEPT - { - #ifdef EA_SYSTEM_BIG_ENDIAN - heap.mnCapacity = (cap << 1) | kHeapMask; - #else - heap.mnCapacity = (cap | kHeapMask); - #endif - } - - inline size_type GetHeapCapacity() const EA_NOEXCEPT - { - #ifdef EA_SYSTEM_BIG_ENDIAN - return (heap.mnCapacity >> 1); - #else - return (heap.mnCapacity & ~kHeapMask); - #endif - } - - inline void Copy(Layout& dst, const Layout& src) EA_NOEXCEPT { dst.raw = src.raw; } - inline void Move(Layout& dst, Layout& src) EA_NOEXCEPT { eastl::swap(dst.raw, src.raw); } - inline void Swap(Layout& a, Layout& b) EA_NOEXCEPT { eastl::swap(a.raw, b.raw); } - - inline void ResetToSSO() EA_NOEXCEPT { *SSOBeginPtr() = 0; SetSSOSize(0); } - }; - - eastl::compressed_pair<Layout, allocator_type> mPair; - - inline Layout& internalLayout() EA_NOEXCEPT { return mPair.first(); } - inline const Layout& internalLayout() const EA_NOEXCEPT { return mPair.first(); } - inline allocator_type& internalAllocator() EA_NOEXCEPT { return mPair.second(); } - inline const allocator_type& internalAllocator() const EA_NOEXCEPT { return mPair.second(); } - - public: - // Constructor, destructor - basic_string() EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(EASTL_BASIC_STRING_DEFAULT_ALLOCATOR)); - explicit basic_string(const allocator_type& allocator) EA_NOEXCEPT; - basic_string(const this_type& x, size_type position, size_type n = npos); - basic_string(const value_type* p, size_type n, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - EASTL_STRING_EXPLICIT basic_string(const value_type* p, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - basic_string(size_type n, value_type c, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - basic_string(const this_type& x); - basic_string(const this_type& x, const allocator_type& allocator); - basic_string(const value_type* pBegin, const value_type* pEnd, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - basic_string(CtorDoNotInitialize, size_type n, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - basic_string(CtorSprintf, const value_type* pFormat, ...); - basic_string(std::initializer_list<value_type> init, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - - basic_string(this_type&& x) EA_NOEXCEPT; - basic_string(this_type&& x, const allocator_type& allocator); - - explicit basic_string(const view_type& sv, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - basic_string(const view_type& sv, size_type position, size_type n, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - - template <typename OtherCharType> - basic_string(CtorConvert, const OtherCharType* p, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - - template <typename OtherCharType> - basic_string(CtorConvert, const OtherCharType* p, size_type n, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); - - template <typename OtherStringType> // Unfortunately we need the CtorConvert here because otherwise this function would collide with the value_type* constructor. - basic_string(CtorConvert, const OtherStringType& x); - - ~basic_string(); - - // Allocator - const allocator_type& get_allocator() const EA_NOEXCEPT; - allocator_type& get_allocator() EA_NOEXCEPT; - void set_allocator(const allocator_type& allocator); - - // Implicit conversion operator - operator basic_string_view<T>() const EA_NOEXCEPT; - - // Operator= - this_type& operator=(const this_type& x); - this_type& operator=(const value_type* p); - this_type& operator=(value_type c); - this_type& operator=(std::initializer_list<value_type> ilist); - this_type& operator=(view_type v); - this_type& operator=(this_type&& x); // TODO(c++17): noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value); - - #if EASTL_OPERATOR_EQUALS_OTHER_ENABLED - this_type& operator=(value_type* p) { return operator=((const value_type*)p); } // We need this because otherwise the const value_type* version can collide with the const OtherStringType& version below. - - template <typename OtherCharType> - this_type& operator=(const OtherCharType* p); - - template <typename OtherStringType> - this_type& operator=(const OtherStringType& x); - #endif - - void swap(this_type& x); // TODO(c++17): noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value || allocator_traits<Allocator>::is_always_equal::value); - - // Assignment operations - this_type& assign(const this_type& x); - this_type& assign(const this_type& x, size_type position, size_type n = npos); - this_type& assign(const value_type* p, size_type n); - this_type& assign(const value_type* p); - this_type& assign(size_type n, value_type c); - this_type& assign(const value_type* pBegin, const value_type* pEnd); - this_type& assign(this_type&& x); // TODO(c++17): noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value); - this_type& assign(std::initializer_list<value_type>); - - template <typename OtherCharType> - this_type& assign_convert(const OtherCharType* p); - - template <typename OtherCharType> - this_type& assign_convert(const OtherCharType* p, size_type n); - - template <typename OtherStringType> - this_type& assign_convert(const OtherStringType& x); - - // Iterators. - iterator begin() EA_NOEXCEPT; // Expanded in source code as: mpBegin - const_iterator begin() const EA_NOEXCEPT; // Expanded in source code as: mpBegin - const_iterator cbegin() const EA_NOEXCEPT; - - iterator end() EA_NOEXCEPT; // Expanded in source code as: mpEnd - const_iterator end() const EA_NOEXCEPT; // Expanded in source code as: mpEnd - const_iterator cend() const EA_NOEXCEPT; - - reverse_iterator rbegin() EA_NOEXCEPT; - const_reverse_iterator rbegin() const EA_NOEXCEPT; - const_reverse_iterator crbegin() const EA_NOEXCEPT; - - reverse_iterator rend() EA_NOEXCEPT; - const_reverse_iterator rend() const EA_NOEXCEPT; - const_reverse_iterator crend() const EA_NOEXCEPT; - - - // Size-related functionality - bool empty() const EA_NOEXCEPT; - size_type size() const EA_NOEXCEPT; - size_type length() const EA_NOEXCEPT; - size_type max_size() const EA_NOEXCEPT; - size_type capacity() const EA_NOEXCEPT; - void resize(size_type n, value_type c); - void resize(size_type n); - void reserve(size_type = 0); - void set_capacity(size_type n = npos); // Revises the capacity to the user-specified value. Resizes the container to match the capacity if the requested capacity n is less than the current size. If n == npos then the capacity is reallocated (if necessary) such that capacity == size. - void force_size(size_type n); // Unilaterally moves the string end position (mpEnd) to the given location. Useful for when the user writes into the string via some extenal means such as C strcpy or sprintf. This allows for more efficient use than using resize to achieve this. - void shrink_to_fit(); - - // Raw access - const value_type* data() const EA_NOEXCEPT; - value_type* data() EA_NOEXCEPT; - const value_type* c_str() const EA_NOEXCEPT; - - // Element access - reference operator[](size_type n); - const_reference operator[](size_type n) const; - reference at(size_type n); - const_reference at(size_type n) const; - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; - - // Append operations - this_type& operator+=(const this_type& x); - this_type& operator+=(const value_type* p); - this_type& operator+=(value_type c); - - this_type& append(const this_type& x); - this_type& append(const this_type& x, size_type position, size_type n = npos); - this_type& append(const value_type* p, size_type n); - this_type& append(const value_type* p); - this_type& append(size_type n, value_type c); - this_type& append(const value_type* pBegin, const value_type* pEnd); - - this_type& append_sprintf_va_list(const value_type* pFormat, va_list arguments); - this_type& append_sprintf(const value_type* pFormat, ...); - - template <typename OtherCharType> - this_type& append_convert(const OtherCharType* p); - - template <typename OtherCharType> - this_type& append_convert(const OtherCharType* p, size_type n); - - template <typename OtherStringType> - this_type& append_convert(const OtherStringType& x); - - void push_back(value_type c); - void pop_back(); - - // Insertion operations - this_type& insert(size_type position, const this_type& x); - this_type& insert(size_type position, const this_type& x, size_type beg, size_type n); - this_type& insert(size_type position, const value_type* p, size_type n); - this_type& insert(size_type position, const value_type* p); - this_type& insert(size_type position, size_type n, value_type c); - iterator insert(const_iterator p, value_type c); - iterator insert(const_iterator p, size_type n, value_type c); - iterator insert(const_iterator p, const value_type* pBegin, const value_type* pEnd); - iterator insert(const_iterator p, std::initializer_list<value_type>); - - // Erase operations - this_type& erase(size_type position = 0, size_type n = npos); - iterator erase(const_iterator p); - iterator erase(const_iterator pBegin, const_iterator pEnd); - reverse_iterator erase(reverse_iterator position); - reverse_iterator erase(reverse_iterator first, reverse_iterator last); - void clear() EA_NOEXCEPT; - - // Detach memory - pointer detach() EA_NOEXCEPT; - - // Replacement operations - this_type& replace(size_type position, size_type n, const this_type& x); - this_type& replace(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2 = npos); - this_type& replace(size_type position, size_type n1, const value_type* p, size_type n2); - this_type& replace(size_type position, size_type n1, const value_type* p); - this_type& replace(size_type position, size_type n1, size_type n2, value_type c); - this_type& replace(const_iterator first, const_iterator last, const this_type& x); - this_type& replace(const_iterator first, const_iterator last, const value_type* p, size_type n); - this_type& replace(const_iterator first, const_iterator last, const value_type* p); - this_type& replace(const_iterator first, const_iterator last, size_type n, value_type c); - this_type& replace(const_iterator first, const_iterator last, const value_type* pBegin, const value_type* pEnd); - size_type copy(value_type* p, size_type n, size_type position = 0) const; - - // Find operations - size_type find(const this_type& x, size_type position = 0) const EA_NOEXCEPT; - size_type find(const value_type* p, size_type position = 0) const; - size_type find(const value_type* p, size_type position, size_type n) const; - size_type find(value_type c, size_type position = 0) const EA_NOEXCEPT; - - // Reverse find operations - size_type rfind(const this_type& x, size_type position = npos) const EA_NOEXCEPT; - size_type rfind(const value_type* p, size_type position = npos) const; - size_type rfind(const value_type* p, size_type position, size_type n) const; - size_type rfind(value_type c, size_type position = npos) const EA_NOEXCEPT; - - // Find first-of operations - size_type find_first_of(const this_type& x, size_type position = 0) const EA_NOEXCEPT; - size_type find_first_of(const value_type* p, size_type position = 0) const; - size_type find_first_of(const value_type* p, size_type position, size_type n) const; - size_type find_first_of(value_type c, size_type position = 0) const EA_NOEXCEPT; - - // Find last-of operations - size_type find_last_of(const this_type& x, size_type position = npos) const EA_NOEXCEPT; - size_type find_last_of(const value_type* p, size_type position = npos) const; - size_type find_last_of(const value_type* p, size_type position, size_type n) const; - size_type find_last_of(value_type c, size_type position = npos) const EA_NOEXCEPT; - - // Find first not-of operations - size_type find_first_not_of(const this_type& x, size_type position = 0) const EA_NOEXCEPT; - size_type find_first_not_of(const value_type* p, size_type position = 0) const; - size_type find_first_not_of(const value_type* p, size_type position, size_type n) const; - size_type find_first_not_of(value_type c, size_type position = 0) const EA_NOEXCEPT; - - // Find last not-of operations - size_type find_last_not_of(const this_type& x, size_type position = npos) const EA_NOEXCEPT; - size_type find_last_not_of(const value_type* p, size_type position = npos) const; - size_type find_last_not_of(const value_type* p, size_type position, size_type n) const; - size_type find_last_not_of(value_type c, size_type position = npos) const EA_NOEXCEPT; - - // Substring functionality - this_type substr(size_type position = 0, size_type n = npos) const; - - // Comparison operations - int compare(const this_type& x) const EA_NOEXCEPT; - int compare(size_type pos1, size_type n1, const this_type& x) const; - int compare(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2) const; - int compare(const value_type* p) const; - int compare(size_type pos1, size_type n1, const value_type* p) const; - int compare(size_type pos1, size_type n1, const value_type* p, size_type n2) const; - static int compare(const value_type* pBegin1, const value_type* pEnd1, const value_type* pBegin2, const value_type* pEnd2); - - // Case-insensitive comparison functions. Not part of C++ this_type. Only ASCII-level locale functionality is supported. Thus this is not suitable for localization purposes. - int comparei(const this_type& x) const EA_NOEXCEPT; - int comparei(const value_type* p) const; - static int comparei(const value_type* pBegin1, const value_type* pEnd1, const value_type* pBegin2, const value_type* pEnd2); - - // Misc functionality, not part of C++ this_type. - void make_lower(); - void make_upper(); - void ltrim(); - void rtrim(); - void trim(); - void ltrim(const value_type* p); - void rtrim(const value_type* p); - void trim(const value_type* p); - this_type left(size_type n) const; - this_type right(size_type n) const; - this_type& sprintf_va_list(const value_type* pFormat, va_list arguments); - this_type& sprintf(const value_type* pFormat, ...); - - bool validate() const EA_NOEXCEPT; - int validate_iterator(const_iterator i) const EA_NOEXCEPT; - - - protected: - // Helper functions for initialization/insertion operations. - value_type* DoAllocate(size_type n); - void DoFree(value_type* p, size_type n); - size_type GetNewCapacity(size_type currentCapacity); - size_type GetNewCapacity(size_type currentCapacity, size_type minimumGrowSize); - void AllocateSelf(); - void AllocateSelf(size_type n); - void DeallocateSelf(); - iterator InsertInternal(const_iterator p, value_type c); - void RangeInitialize(const value_type* pBegin, const value_type* pEnd); - void RangeInitialize(const value_type* pBegin); - void SizeInitialize(size_type n, value_type c); - - bool IsSSO() const EA_NOEXCEPT; - - void ThrowLengthException() const; - void ThrowRangeException() const; - void ThrowInvalidArgumentException() const; - - #if EASTL_OPERATOR_EQUALS_OTHER_ENABLED - template <typename CharType> - void DoAssignConvert(CharType c, true_type); - - template <typename StringType> - void DoAssignConvert(const StringType& x, false_type); - #endif - - // Replacements for STL template functions. - static const value_type* CharTypeStringFindEnd(const value_type* pBegin, const value_type* pEnd, value_type c); - static const value_type* CharTypeStringRFind(const value_type* pRBegin, const value_type* pREnd, const value_type c); - static const value_type* CharTypeStringSearch(const value_type* p1Begin, const value_type* p1End, const value_type* p2Begin, const value_type* p2End); - static const value_type* CharTypeStringRSearch(const value_type* p1Begin, const value_type* p1End, const value_type* p2Begin, const value_type* p2End); - static const value_type* CharTypeStringFindFirstOf(const value_type* p1Begin, const value_type* p1End, const value_type* p2Begin, const value_type* p2End); - static const value_type* CharTypeStringRFindFirstOf(const value_type* p1RBegin, const value_type* p1REnd, const value_type* p2Begin, const value_type* p2End); - static const value_type* CharTypeStringFindFirstNotOf(const value_type* p1Begin, const value_type* p1End, const value_type* p2Begin, const value_type* p2End); - static const value_type* CharTypeStringRFindFirstNotOf(const value_type* p1RBegin, const value_type* p1REnd, const value_type* p2Begin, const value_type* p2End); - - }; // basic_string - - - - - - /////////////////////////////////////////////////////////////////////////////// - // basic_string - /////////////////////////////////////////////////////////////////////////////// - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string() EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(EASTL_BASIC_STRING_DEFAULT_ALLOCATOR)) - : mPair(allocator_type(EASTL_BASIC_STRING_DEFAULT_NAME)) - { - AllocateSelf(); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string(const allocator_type& allocator) EA_NOEXCEPT - : mPair(allocator) - { - AllocateSelf(); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string(const this_type& x) - : mPair(x.get_allocator()) - { - RangeInitialize(x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>::basic_string(const this_type& x, const allocator_type& allocator) - : mPair(allocator) - { - RangeInitialize(x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - template <typename OtherStringType> - inline basic_string<T, Allocator>::basic_string(CtorConvert, const OtherStringType& x) - : mPair(x.get_allocator()) - { - AllocateSelf(); - append_convert(x.c_str(), x.length()); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>::basic_string(const this_type& x, size_type position, size_type n) - : mPair(x.get_allocator()) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if (EASTL_UNLIKELY(position > x.internalLayout().GetSize())) // 21.4.2 p4 - { - ThrowRangeException(); - AllocateSelf(); - } - else - RangeInitialize( - x.internalLayout().BeginPtr() + position, - x.internalLayout().BeginPtr() + position + eastl::min_alt(n, x.internalLayout().GetSize() - position)); - #else - RangeInitialize( - x.internalLayout().BeginPtr() + position, - x.internalLayout().BeginPtr() + position + eastl::min_alt(n, x.internalLayout().GetSize() - position)); - #endif - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string(const value_type* p, size_type n, const allocator_type& allocator) - : mPair(allocator) - { - RangeInitialize(p, p + n); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string(const view_type& sv, const allocator_type& allocator) - : basic_string(sv.data(), sv.size(), allocator) - { - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string(const view_type& sv, size_type position, size_type n, const allocator_type& allocator) - : basic_string(sv.substr(position, n), allocator) - { - } - - - template <typename T, typename Allocator> - template <typename OtherCharType> - inline basic_string<T, Allocator>::basic_string(CtorConvert, const OtherCharType* p, const allocator_type& allocator) - : mPair(allocator) - { - AllocateSelf(); // In this case we are converting from one string encoding to another, and we - append_convert(p); // implement this in the simplest way, by simply default-constructing and calling assign. - } - - - template <typename T, typename Allocator> - template <typename OtherCharType> - inline basic_string<T, Allocator>::basic_string(CtorConvert, const OtherCharType* p, size_type n, const allocator_type& allocator) - : mPair(allocator) - { - AllocateSelf(); // In this case we are converting from one string encoding to another, and we - append_convert(p, n); // implement this in the simplest way, by simply default-constructing and calling assign. - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string(const value_type* p, const allocator_type& allocator) - : mPair(allocator) - { - RangeInitialize(p); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string(size_type n, value_type c, const allocator_type& allocator) - : mPair(allocator) - { - SizeInitialize(n, c); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::basic_string(const value_type* pBegin, const value_type* pEnd, const allocator_type& allocator) - : mPair(allocator) - { - RangeInitialize(pBegin, pEnd); - } - - - // CtorDoNotInitialize exists so that we can create a version that allocates but doesn't - // initialize but also doesn't collide with any other constructor declaration. - template <typename T, typename Allocator> - basic_string<T, Allocator>::basic_string(CtorDoNotInitialize /*unused*/, size_type n, const allocator_type& allocator) - : mPair(allocator) - { - // Note that we do not call SizeInitialize here. - AllocateSelf(n); - internalLayout().SetSize(0); - *internalLayout().EndPtr() = 0; - } - - - // CtorSprintf exists so that we can create a version that does a variable argument - // sprintf but also doesn't collide with any other constructor declaration. - template <typename T, typename Allocator> - basic_string<T, Allocator>::basic_string(CtorSprintf /*unused*/, const value_type* pFormat, ...) - : mPair() - { - const size_type n = (size_type)CharStrlen(pFormat); - AllocateSelf(n); - internalLayout().SetSize(0); - - va_list arguments; - va_start(arguments, pFormat); - append_sprintf_va_list(pFormat, arguments); - va_end(arguments); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>::basic_string(std::initializer_list<value_type> init, const allocator_type& allocator) - : mPair(allocator) - { - RangeInitialize(init.begin(), init.end()); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>::basic_string(this_type&& x) EA_NOEXCEPT - : mPair(x.get_allocator()) - { - internalLayout() = eastl::move(x.internalLayout()); - x.AllocateSelf(); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>::basic_string(this_type&& x, const allocator_type& allocator) - : mPair(allocator) - { - if(get_allocator() == x.get_allocator()) // If we can borrow from x... - { - internalLayout() = eastl::move(x.internalLayout()); - x.AllocateSelf(); - } - else if(x.internalLayout().BeginPtr()) - { - RangeInitialize(x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - // Let x destruct its own items. - } - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>::~basic_string() - { - DeallocateSelf(); - } - - - template <typename T, typename Allocator> - inline const typename basic_string<T, Allocator>::allocator_type& - basic_string<T, Allocator>::get_allocator() const EA_NOEXCEPT - { - return internalAllocator(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::allocator_type& - basic_string<T, Allocator>::get_allocator() EA_NOEXCEPT - { - return internalAllocator(); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::set_allocator(const allocator_type& allocator) - { - get_allocator() = allocator; - } - - - template <typename T, typename Allocator> - inline const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::data() const EA_NOEXCEPT - { - return internalLayout().BeginPtr(); - } - - - template <typename T, typename Allocator> - inline const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::c_str() const EA_NOEXCEPT - { - return internalLayout().BeginPtr(); - } - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::data() EA_NOEXCEPT - { - return internalLayout().BeginPtr(); - } - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::begin() EA_NOEXCEPT - { - return internalLayout().BeginPtr(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::end() EA_NOEXCEPT - { - return internalLayout().EndPtr(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_iterator - basic_string<T, Allocator>::begin() const EA_NOEXCEPT - { - return internalLayout().BeginPtr(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_iterator - basic_string<T, Allocator>::cbegin() const EA_NOEXCEPT - { - return internalLayout().BeginPtr(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_iterator - basic_string<T, Allocator>::end() const EA_NOEXCEPT - { - return internalLayout().EndPtr(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_iterator - basic_string<T, Allocator>::cend() const EA_NOEXCEPT - { - return internalLayout().EndPtr(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::reverse_iterator - basic_string<T, Allocator>::rbegin() EA_NOEXCEPT - { - return reverse_iterator(internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::reverse_iterator - basic_string<T, Allocator>::rend() EA_NOEXCEPT - { - return reverse_iterator(internalLayout().BeginPtr()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_reverse_iterator - basic_string<T, Allocator>::rbegin() const EA_NOEXCEPT - { - return const_reverse_iterator(internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_reverse_iterator - basic_string<T, Allocator>::crbegin() const EA_NOEXCEPT - { - return const_reverse_iterator(internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_reverse_iterator - basic_string<T, Allocator>::rend() const EA_NOEXCEPT - { - return const_reverse_iterator(internalLayout().BeginPtr()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_reverse_iterator - basic_string<T, Allocator>::crend() const EA_NOEXCEPT - { - return const_reverse_iterator(internalLayout().BeginPtr()); - } - - - template <typename T, typename Allocator> - inline bool basic_string<T, Allocator>::empty() const EA_NOEXCEPT - { - return (internalLayout().GetSize() == 0); - } - - - template <typename T, typename Allocator> - inline bool basic_string<T, Allocator>::IsSSO() const EA_NOEXCEPT - { - return internalLayout().IsSSO(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::size() const EA_NOEXCEPT - { - return internalLayout().GetSize(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::length() const EA_NOEXCEPT - { - return internalLayout().GetSize(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::max_size() const EA_NOEXCEPT - { - return kMaxSize; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::capacity() const EA_NOEXCEPT - { - if (internalLayout().IsHeap()) - { - return internalLayout().GetHeapCapacity(); - } - return SSOLayout::SSO_CAPACITY; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_reference - basic_string<T, Allocator>::operator[](size_type n) const - { - #if EASTL_ASSERT_ENABLED // We allow the user to reference the trailing 0 char without asserting. Perhaps we shouldn't. - if(EASTL_UNLIKELY(n > internalLayout().GetSize())) - EASTL_FAIL_MSG("basic_string::operator[] -- out of range"); - #endif - - return internalLayout().BeginPtr()[n]; // Sometimes done as *(mpBegin + n) - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::reference - basic_string<T, Allocator>::operator[](size_type n) - { - #if EASTL_ASSERT_ENABLED // We allow the user to reference the trailing 0 char without asserting. Perhaps we shouldn't. - if(EASTL_UNLIKELY(n > internalLayout().GetSize())) - EASTL_FAIL_MSG("basic_string::operator[] -- out of range"); - #endif - - return internalLayout().BeginPtr()[n]; // Sometimes done as *(mpBegin + n) - } - - - template <typename T, typename Allocator> - basic_string<T,Allocator>::operator basic_string_view<T>() const EA_NOEXCEPT - { - return basic_string_view<T>(data(), size()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(const this_type& x) - { - if(&x != this) - { - #if EASTL_ALLOCATOR_COPY_ENABLED - bool bSlowerPathwayRequired = (get_allocator() != x.get_allocator()); - #else - bool bSlowerPathwayRequired = false; - #endif - - if(bSlowerPathwayRequired) - { - set_capacity(0); // Must use set_capacity instead of clear because set_capacity frees our memory, unlike clear. - - #if EASTL_ALLOCATOR_COPY_ENABLED - get_allocator() = x.get_allocator(); - #endif - } - - assign(x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - return *this; - } - - - #if EASTL_OPERATOR_EQUALS_OTHER_ENABLED - template <typename T, typename Allocator> - template <typename CharType> - inline void basic_string<T, Allocator>::DoAssignConvert(CharType c, true_type) - { - assign_convert(&c, 1); // Call this version of append because it will result in the encoding-converting append being used. - } - - - template <typename T, typename Allocator> - template <typename StringType> - inline void basic_string<T, Allocator>::DoAssignConvert(const StringType& x, false_type) - { - //if(&x != this) // Unnecessary because &x cannot possibly equal this. - { - #if EASTL_ALLOCATOR_COPY_ENABLED - get_allocator() = x.get_allocator(); - #endif - - assign_convert(x.c_str(), x.length()); - } - } - - - template <typename T, typename Allocator> - template <typename OtherStringType> - inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(const OtherStringType& x) - { - clear(); - DoAssignConvert(x, is_integral<OtherStringType>()); - return *this; - } - - - template <typename T, typename Allocator> - template <typename OtherCharType> - inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(const OtherCharType* p) - { - return assign_convert(p); - } - #endif - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(const value_type* p) - { - return assign(p, p + CharStrlen(p)); - } - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(value_type c) - { - return assign((size_type)1, c); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(this_type&& x) - { - return assign(eastl::move(x)); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(std::initializer_list<value_type> ilist) - { - return assign(ilist.begin(), ilist.end()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(view_type v) - { - return assign(v.data(), static_cast<this_type::size_type>(v.size())); - } - - - template <typename T, typename Allocator> - void basic_string<T, Allocator>::resize(size_type n, value_type c) - { - const size_type s = internalLayout().GetSize(); - - if(n < s) - erase(internalLayout().BeginPtr() + n, internalLayout().EndPtr()); - else if(n > s) - append(n - s, c); - } - - - template <typename T, typename Allocator> - void basic_string<T, Allocator>::resize(size_type n) - { - // C++ basic_string specifies that resize(n) is equivalent to resize(n, value_type()). - // For built-in types, value_type() is the same as zero (value_type(0)). - // We can improve the efficiency (especially for long strings) of this - // string class by resizing without assigning to anything. - - const size_type s = internalLayout().GetSize(); - - if(n < s) - erase(internalLayout().BeginPtr() + n, internalLayout().EndPtr()); - else if(n > s) - { - append(n - s, value_type()); - } - } - - - template <typename T, typename Allocator> - void basic_string<T, Allocator>::reserve(size_type n) - { - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY(n > max_size())) - ThrowLengthException(); - #endif - - // C++20 says if the passed in capacity is less than the current capacity we do not shrink - // If new_cap is less than or equal to the current capacity(), there is no effect. - // http://en.cppreference.com/w/cpp/string/basic_string/reserve - - n = eastl::max_alt(n, internalLayout().GetSize()); // Calculate the new capacity, which needs to be >= container size. - - if(n > capacity()) - set_capacity(n); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::shrink_to_fit() - { - set_capacity(internalLayout().GetSize()); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::set_capacity(size_type n) - { - if(n == npos) - // If the user wants to set the capacity to equal the current size... - // '-1' because we pretend that we didn't allocate memory for the terminating 0. - n = internalLayout().GetSize(); - else if(n < internalLayout().GetSize()) - { - internalLayout().SetSize(n); - *internalLayout().EndPtr() = 0; - } - - if((n < capacity() && internalLayout().IsHeap()) || (n > capacity())) - { - // In here the string is transition from heap->heap, heap->sso or sso->heap - - if(EASTL_LIKELY(n)) - { - - if(n <= SSOLayout::SSO_CAPACITY) - { - // heap->sso - // A heap based layout wants to reduce its size to within sso capacity - // An sso layout wanting to reduce its capacity will not get in here - pointer pOldBegin = internalLayout().BeginPtr(); - const size_type nOldCap = internalLayout().GetHeapCapacity(); - - CharStringUninitializedCopy(pOldBegin, pOldBegin + n, internalLayout().SSOBeginPtr()); - internalLayout().SetSSOSize(n); - *internalLayout().SSOEndPtr() = 0; - - DoFree(pOldBegin, nOldCap + 1); - - return; - } - - pointer pNewBegin = DoAllocate(n + 1); // We need the + 1 to accomodate the trailing 0. - size_type nSavedSize = internalLayout().GetSize(); // save the size in case we transition from sso->heap - - pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pNewBegin); - *pNewEnd = 0; - - DeallocateSelf(); - - internalLayout().SetHeapBeginPtr(pNewBegin); - internalLayout().SetHeapCapacity(n); - internalLayout().SetHeapSize(nSavedSize); - } - else - { - DeallocateSelf(); - AllocateSelf(); - } - } - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::force_size(size_type n) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(n > capacity())) - ThrowRangeException(); - #elif EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(n > capacity())) - EASTL_FAIL_MSG("basic_string::force_size -- out of range"); - #endif - - internalLayout().SetSize(n); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::clear() EA_NOEXCEPT - { - internalLayout().SetSize(0); - *internalLayout().BeginPtr() = value_type(0); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::pointer - basic_string<T, Allocator>::detach() EA_NOEXCEPT - { - // The detach function is an extension function which simply forgets the - // owned pointer. It doesn't free it but rather assumes that the user - // does. If the string is utilizing the short-string-optimization when a - // detach is requested, a copy of the string into a seperate memory - // allocation occurs and the owning pointer is given to the user who is - // responsible for freeing the memory. - - pointer pDetached = nullptr; - - if (internalLayout().IsSSO()) - { - const size_type n = internalLayout().GetSize() + 1; // +1' so that we have room for the terminating 0. - pDetached = DoAllocate(n); - pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pDetached); - *pNewEnd = 0; - } - else - { - pDetached = internalLayout().BeginPtr(); - } - - AllocateSelf(); // reset to string to empty - return pDetached; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_reference - basic_string<T, Allocator>::at(size_type n) const - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(n >= internalLayout().GetSize())) - ThrowRangeException(); - #elif EASTL_ASSERT_ENABLED // We assert if the user references the trailing 0 char. - if(EASTL_UNLIKELY(n >= internalLayout().GetSize())) - EASTL_FAIL_MSG("basic_string::at -- out of range"); - #endif - - return internalLayout().BeginPtr()[n]; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::reference - basic_string<T, Allocator>::at(size_type n) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(n >= internalLayout().GetSize())) - ThrowRangeException(); - #elif EASTL_ASSERT_ENABLED // We assert if the user references the trailing 0 char. - if(EASTL_UNLIKELY(n >= internalLayout().GetSize())) - EASTL_FAIL_MSG("basic_string::at -- out of range"); - #endif - - return internalLayout().BeginPtr()[n]; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::reference - basic_string<T, Allocator>::front() - { - #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED - if (EASTL_UNLIKELY(internalLayout().GetSize() <= 0)) // We assert if the user references the trailing 0 char. - EASTL_FAIL_MSG("basic_string::front -- empty string"); - #else - // We allow the user to reference the trailing 0 char without asserting. - #endif - - return *internalLayout().BeginPtr(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_reference - basic_string<T, Allocator>::front() const - { - #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED - if (EASTL_UNLIKELY(internalLayout().GetSize() <= 0)) // We assert if the user references the trailing 0 char. - EASTL_FAIL_MSG("basic_string::front -- empty string"); - #else - // We allow the user to reference the trailing 0 char without asserting. - #endif - - return *internalLayout().BeginPtr(); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::reference - basic_string<T, Allocator>::back() - { - #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED - if (EASTL_UNLIKELY(internalLayout().GetSize() <= 0)) // We assert if the user references the trailing 0 char. - EASTL_FAIL_MSG("basic_string::back -- empty string"); - #else - // We allow the user to reference the trailing 0 char without asserting. - #endif - - return *(internalLayout().EndPtr() - 1); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::const_reference - basic_string<T, Allocator>::back() const - { - #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED - if (EASTL_UNLIKELY(internalLayout().GetSize() <= 0)) // We assert if the user references the trailing 0 char. - EASTL_FAIL_MSG("basic_string::back -- empty string"); - #else - // We allow the user to reference the trailing 0 char without asserting. - #endif - - return *(internalLayout().EndPtr() - 1); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::operator+=(const this_type& x) - { - return append(x); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::operator+=(const value_type* p) - { - return append(p); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::operator+=(value_type c) - { - push_back(c); - return *this; - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::append(const this_type& x) - { - return append(x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::append(const this_type& x, size_type position, size_type n) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position >= x.internalLayout().GetSize())) // position must be < x.mpEnd, but position + n may be > mpEnd. - ThrowRangeException(); - #endif - - return append(x.internalLayout().BeginPtr() + position, - x.internalLayout().BeginPtr() + position + eastl::min_alt(n, x.internalLayout().GetSize() - position)); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::append(const value_type* p, size_type n) - { - return append(p, p + n); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::append(const value_type* p) - { - return append(p, p + CharStrlen(p)); - } - - - template <typename T, typename Allocator> - template <typename OtherCharType> - basic_string<T, Allocator>& basic_string<T, Allocator>::append_convert(const OtherCharType* pOther) - { - return append_convert(pOther, (size_type)CharStrlen(pOther)); - } - - - template <typename T, typename Allocator> - template <typename OtherStringType> - basic_string<T, Allocator>& basic_string<T, Allocator>::append_convert(const OtherStringType& x) - { - return append_convert(x.c_str(), x.length()); - } - - - template <typename T, typename Allocator> - template <typename OtherCharType> - basic_string<T, Allocator>& basic_string<T, Allocator>::append_convert(const OtherCharType* pOther, size_type n) - { - // Question: What do we do in the case that we have an illegally encoded source string? - // This can happen with UTF8 strings. Do we throw an exception or do we ignore the input? - // One argument is that it's not a string class' job to handle the security aspects of a - // program and the higher level application code should be verifying UTF8 string validity, - // and thus we should do the friendly thing and ignore the invalid characters as opposed - // to making the user of this function handle exceptions that are easily forgotten. - - const size_t kBufferSize = 512; - value_type selfBuffer[kBufferSize]; // This assumes that value_type is one of char8_t, char16_t, char32_t, or wchar_t. Or more importantly, a type with a trivial constructor and destructor. - value_type* const selfBufferEnd = selfBuffer + kBufferSize; - const OtherCharType* pOtherEnd = pOther + n; - - while(pOther != pOtherEnd) - { - value_type* pSelfBufferCurrent = selfBuffer; - DecodePart(pOther, pOtherEnd, pSelfBufferCurrent, selfBufferEnd); // Write pOther to pSelfBuffer, converting encoding as we go. We currently ignore the return value, as we don't yet have a plan for handling encoding errors. - append(selfBuffer, pSelfBufferCurrent); - } - - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::append(size_type n, value_type c) - { - if (n > 0) - { - const size_type nSize = internalLayout().GetSize(); - const size_type nCapacity = capacity(); - - if((nSize + n) > nCapacity) - reserve(GetNewCapacity(nCapacity, (nSize + n) - nCapacity)); - - pointer pNewEnd = CharStringUninitializedFillN(internalLayout().EndPtr(), n, c); - *pNewEnd = 0; - internalLayout().SetSize(nSize + n); - } - - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::append(const value_type* pBegin, const value_type* pEnd) - { - if(pBegin != pEnd) - { - const size_type nOldSize = internalLayout().GetSize(); - const size_type n = (size_type)(pEnd - pBegin); - const size_type nCapacity = capacity(); - const size_type nNewSize = nOldSize + n; - - if(nNewSize > nCapacity) - { - const size_type nLength = GetNewCapacity(nCapacity, nNewSize - nCapacity); - - pointer pNewBegin = DoAllocate(nLength + 1); - - pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), internalLayout().EndPtr(), pNewBegin); - pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, pNewEnd); - *pNewEnd = 0; - - DeallocateSelf(); - internalLayout().SetHeapBeginPtr(pNewBegin); - internalLayout().SetHeapCapacity(nLength); - internalLayout().SetHeapSize(nNewSize); - } - else - { - pointer pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, internalLayout().EndPtr()); - *pNewEnd = 0; - internalLayout().SetSize(nNewSize); - } - } - - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::append_sprintf_va_list(const value_type* pFormat, va_list arguments) - { - // From unofficial C89 extension documentation: - // The vsnprintf returns the number of characters written into the array, - // not counting the terminating null character, or a negative value - // if count or more characters are requested to be generated. - // An error can occur while converting a value for output. - - // From the C99 standard: - // The vsnprintf function returns the number of characters that would have - // been written had n been sufficiently large, not counting the terminating - // null character, or a negative value if an encoding error occurred. - // Thus, the null-terminated output has been completely written if and only - // if the returned value is nonnegative and less than n. - - // https://www.freebsd.org/cgi/man.cgi?query=vswprintf&sektion=3&manpath=freebsd-release-ports - // https://www.freebsd.org/cgi/man.cgi?query=snprintf&manpath=SuSE+Linux/i386+11.3 - // Well its time to go on an adventure... - // C99 vsnprintf states that a buffer size of zero returns the number of characters that would - // be written to the buffer irrelevant of whether the buffer is a nullptr - // But C99 vswprintf for wchar_t changes the behaviour of the return to instead say that it - // "will fail if n or more wide characters were requested to be written", so - // calling vswprintf with a buffer size of zero always returns -1 - // unless... you are MSVC where they deviate from the std and say if the buffer is NULL - // and the size is zero it will return the number of characters written or if we are using - // EAStdC which also does the sane behaviour. - -#if !EASTL_OPENSOURCE || defined(EA_PLATFORM_MICROSOFT) - size_type nInitialSize = internalLayout().GetSize(); - int nReturnValue; - - #if EASTL_VA_COPY_ENABLED - va_list argumentsSaved; - va_copy(argumentsSaved, arguments); - #endif - - nReturnValue = eastl::Vsnprintf(nullptr, 0, pFormat, arguments); - - if (nReturnValue > 0) - { - resize(nReturnValue + nInitialSize); - - #if EASTL_VA_COPY_ENABLED - va_end(arguments); - va_copy(arguments, argumentsSaved); - #endif - - nReturnValue = eastl::Vsnprintf(internalLayout().BeginPtr() + nInitialSize, static_cast<size_t>(nReturnValue) + 1, pFormat, arguments); - } - - if (nReturnValue >= 0) - { - internalLayout().SetSize(nInitialSize + nReturnValue); - } - - #if EASTL_VA_COPY_ENABLED - // va_end for arguments will be called by the caller. - va_end(argumentsSaved); - #endif - -#else - size_type nInitialSize = internalLayout().GetSize(); - size_type nInitialRemainingCapacity = internalLayout().GetRemainingCapacity(); - int nReturnValue; - - #if EASTL_VA_COPY_ENABLED - va_list argumentsSaved; - va_copy(argumentsSaved, arguments); - #endif - - nReturnValue = eastl::Vsnprintf(internalLayout().EndPtr(), (size_t)nInitialRemainingCapacity + 1, - pFormat, arguments); - - if(nReturnValue >= (int)(nInitialRemainingCapacity + 1)) // If there wasn't enough capacity... - { - // In this case we definitely have C99 Vsnprintf behaviour. - #if EASTL_VA_COPY_ENABLED - va_end(arguments); - va_copy(arguments, argumentsSaved); - #endif - resize(nInitialSize + nReturnValue); - nReturnValue = eastl::Vsnprintf(internalLayout().BeginPtr() + nInitialSize, (size_t)(nReturnValue + 1), - pFormat, arguments); - } - else if(nReturnValue < 0) // If vsnprintf is non-C99-standard - { - // In this case we either have C89 extension behaviour or C99 behaviour. - size_type n = eastl::max_alt((size_type)(SSOLayout::SSO_CAPACITY - 1), (size_type)(nInitialSize * 2)); - - for(; (nReturnValue < 0) && (n < 1000000); n *= 2) - { - #if EASTL_VA_COPY_ENABLED - va_end(arguments); - va_copy(arguments, argumentsSaved); - #endif - resize(n); - - const size_t nCapacity = (size_t)(n - nInitialSize); - nReturnValue = eastl::Vsnprintf(internalLayout().BeginPtr() + nInitialSize, nCapacity + 1, pFormat, arguments); - - if(nReturnValue == (int)(unsigned)nCapacity) - { - resize(++n); - nReturnValue = eastl::Vsnprintf(internalLayout().BeginPtr() + nInitialSize, nCapacity + 2, pFormat, arguments); - } - } - } - - if(nReturnValue >= 0) - { - internalLayout().SetSize(nInitialSize + nReturnValue); - } - - #if EASTL_VA_COPY_ENABLED - // va_end for arguments will be called by the caller. - va_end(argumentsSaved); - #endif - -#endif // EASTL_OPENSOURCE - - return *this; - } - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::append_sprintf(const value_type* pFormat, ...) - { - va_list arguments; - va_start(arguments, pFormat); - append_sprintf_va_list(pFormat, arguments); - va_end(arguments); - - return *this; - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::push_back(value_type c) - { - append((size_type)1, c); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::pop_back() - { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(internalLayout().GetSize() <= 0)) - EASTL_FAIL_MSG("basic_string::pop_back -- empty string"); - #endif - - internalLayout().EndPtr()[-1] = value_type(0); - internalLayout().SetSize(internalLayout().GetSize() - 1); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::assign(const this_type& x) - { - // The C++11 Standard 21.4.6.3 p6 specifies that assign from this_type assigns contents only and not the allocator. - return assign(x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::assign(const this_type& x, size_type position, size_type n) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > x.internalLayout().GetSize())) - ThrowRangeException(); - #endif - - // The C++11 Standard 21.4.6.3 p6 specifies that assign from this_type assigns contents only and not the allocator. - return assign( - x.internalLayout().BeginPtr() + position, - x.internalLayout().BeginPtr() + position + eastl::min_alt(n, x.internalLayout().GetSize() - position)); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::assign(const value_type* p, size_type n) - { - return assign(p, p + n); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::assign(const value_type* p) - { - return assign(p, p + CharStrlen(p)); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::assign(size_type n, value_type c) - { - if(n <= internalLayout().GetSize()) - { - CharTypeAssignN(internalLayout().BeginPtr(), n, c); - erase(internalLayout().BeginPtr() + n, internalLayout().EndPtr()); - } - else - { - CharTypeAssignN(internalLayout().BeginPtr(), internalLayout().GetSize(), c); - append(n - internalLayout().GetSize(), c); - } - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::assign(const value_type* pBegin, const value_type* pEnd) - { - const size_type n = (size_type)(pEnd - pBegin); - if(n <= internalLayout().GetSize()) - { - memmove(internalLayout().BeginPtr(), pBegin, (size_t)n * sizeof(value_type)); - erase(internalLayout().BeginPtr() + n, internalLayout().EndPtr()); - } - else - { - memmove(internalLayout().BeginPtr(), pBegin, (size_t)(internalLayout().GetSize()) * sizeof(value_type)); - append(pBegin + internalLayout().GetSize(), pEnd); - } - return *this; - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::assign(std::initializer_list<value_type> ilist) - { - return assign(ilist.begin(), ilist.end()); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::assign(this_type&& x) - { - if(get_allocator() == x.get_allocator()) - { - eastl::swap(internalLayout(), x.internalLayout()); - } - else - assign(x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - - return *this; - } - - - template <typename T, typename Allocator> - template <typename OtherCharType> - basic_string<T, Allocator>& basic_string<T, Allocator>::assign_convert(const OtherCharType* p) - { - clear(); - append_convert(p); - return *this; - } - - - template <typename T, typename Allocator> - template <typename OtherCharType> - basic_string<T, Allocator>& basic_string<T, Allocator>::assign_convert(const OtherCharType* p, size_type n) - { - clear(); - append_convert(p, n); - return *this; - } - - - template <typename T, typename Allocator> - template <typename OtherStringType> - basic_string<T, Allocator>& basic_string<T, Allocator>::assign_convert(const OtherStringType& x) - { - clear(); - append_convert(x.data(), x.length()); - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::insert(size_type position, const this_type& x) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY(internalLayout().GetSize() > (max_size() - x.internalLayout().GetSize()))) - ThrowLengthException(); - #endif - - insert(internalLayout().BeginPtr() + position, x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::insert(size_type position, const this_type& x, size_type beg, size_type n) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY((position > internalLayout().GetSize()) || (beg > x.internalLayout().GetSize()))) - ThrowRangeException(); - #endif - - size_type nLength = eastl::min_alt(n, x.internalLayout().GetSize() - beg); - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY(internalLayout().GetSize() > (max_size() - nLength))) - ThrowLengthException(); - #endif - - insert(internalLayout().BeginPtr() + position, x.internalLayout().BeginPtr() + beg, x.internalLayout().BeginPtr() + beg + nLength); - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::insert(size_type position, const value_type* p, size_type n) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY(internalLayout().GetSize() > (max_size() - n))) - ThrowLengthException(); - #endif - - insert(internalLayout().BeginPtr() + position, p, p + n); - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::insert(size_type position, const value_type* p) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - size_type nLength = (size_type)CharStrlen(p); - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY(internalLayout().GetSize() > (max_size() - nLength))) - ThrowLengthException(); - #endif - - insert(internalLayout().BeginPtr() + position, p, p + nLength); - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::insert(size_type position, size_type n, value_type c) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY(internalLayout().GetSize() > (max_size() - n))) - ThrowLengthException(); - #endif - - insert(internalLayout().BeginPtr() + position, n, c); - return *this; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::insert(const_iterator p, value_type c) - { - if(p == internalLayout().EndPtr()) - { - push_back(c); - return internalLayout().EndPtr() - 1; - } - return InsertInternal(p, c); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::insert(const_iterator p, size_type n, value_type c) - { - const difference_type nPosition = (p - internalLayout().BeginPtr()); // Save this because we might reallocate. - - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY((p < internalLayout().BeginPtr()) || (p > internalLayout().EndPtr()))) - EASTL_FAIL_MSG("basic_string::insert -- invalid position"); - #endif - - if(n) // If there is anything to insert... - { - if(internalLayout().GetRemainingCapacity() >= n) // If we have enough capacity... - { - const size_type nElementsAfter = (size_type)(internalLayout().EndPtr() - p); - - if(nElementsAfter >= n) // If there's enough space for the new chars between the insert position and the end... - { - // Ensure we save the size before we do the copy, as we might overwrite the size field with the NULL - // terminator in the edge case where we are inserting enough characters to equal our capacity - const size_type nSavedSize = internalLayout().GetSize(); - CharStringUninitializedCopy((internalLayout().EndPtr() - n) + 1, internalLayout().EndPtr() + 1, internalLayout().EndPtr() + 1); - internalLayout().SetSize(nSavedSize + n); - memmove(const_cast<value_type*>(p) + n, p, (size_t)((nElementsAfter - n) + 1) * sizeof(value_type)); - CharTypeAssignN(const_cast<value_type*>(p), n, c); - } - else - { - pointer pOldEnd = internalLayout().EndPtr(); - #if EASTL_EXCEPTIONS_ENABLED - const size_type nOldSize = internalLayout().GetSize(); - #endif - CharStringUninitializedFillN(internalLayout().EndPtr() + 1, n - nElementsAfter - 1, c); - internalLayout().SetSize(internalLayout().GetSize() + (n - nElementsAfter)); - - #if EASTL_EXCEPTIONS_ENABLED - try - { - #endif - // See comment in if block above - const size_type nSavedSize = internalLayout().GetSize(); - CharStringUninitializedCopy(p, pOldEnd + 1, internalLayout().EndPtr()); - internalLayout().SetSize(nSavedSize + nElementsAfter); - #if EASTL_EXCEPTIONS_ENABLED - } - catch(...) - { - internalLayout().SetSize(nOldSize); - throw; - } - #endif - - CharTypeAssignN(const_cast<value_type*>(p), nElementsAfter + 1, c); - } - } - else - { - const size_type nOldSize = internalLayout().GetSize(); - const size_type nOldCap = capacity(); - const size_type nLength = GetNewCapacity(nOldCap, (nOldSize + n) - nOldCap); - - iterator pNewBegin = DoAllocate(nLength + 1); - - iterator pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); - pNewEnd = CharStringUninitializedFillN(pNewEnd, n, c); - pNewEnd = CharStringUninitializedCopy(p, internalLayout().EndPtr(), pNewEnd); - *pNewEnd = 0; - - DeallocateSelf(); - internalLayout().SetHeapBeginPtr(pNewBegin); - internalLayout().SetHeapCapacity(nLength); - internalLayout().SetHeapSize(nOldSize + n); - } - } - - return internalLayout().BeginPtr() + nPosition; - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::insert(const_iterator p, const value_type* pBegin, const value_type* pEnd) - { - const difference_type nPosition = (p - internalLayout().BeginPtr()); // Save this because we might reallocate. - - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY((p < internalLayout().BeginPtr()) || (p > internalLayout().EndPtr()))) - EASTL_FAIL_MSG("basic_string::insert -- invalid position"); - #endif - - const size_type n = (size_type)(pEnd - pBegin); - - if(n) - { - const bool bCapacityIsSufficient = (internalLayout().GetRemainingCapacity() >= n); - const bool bSourceIsFromSelf = ((pEnd >= internalLayout().BeginPtr()) && (pBegin <= internalLayout().EndPtr())); - - if(bSourceIsFromSelf && internalLayout().IsSSO()) - { - // pBegin to pEnd will be <= this->GetSize(), so stackTemp will guaranteed be an SSO String - // If we are inserting ourself into ourself and we are SSO, then on the recursive call we can - // guarantee 0 or 1 allocation depending if we need to realloc - // We don't do this for Heap strings as then this path may do 1 or 2 allocations instead of - // only 1 allocation when we fall through to the last else case below - const this_type stackTemp(pBegin, pEnd, get_allocator()); - return insert(p, stackTemp.data(), stackTemp.data() + stackTemp.size()); - } - - // If bSourceIsFromSelf is true, then we reallocate. This is because we are - // inserting ourself into ourself and thus both the source and destination - // be modified, making it rather tricky to attempt to do in place. The simplest - // resolution is to reallocate. To consider: there may be a way to implement this - // whereby we don't need to reallocate or can often avoid reallocating. - if(bCapacityIsSufficient && !bSourceIsFromSelf) - { - const size_type nElementsAfter = (size_type)(internalLayout().EndPtr() - p); - - if(nElementsAfter >= n) // If there are enough characters between insert pos and end - { - // Ensure we save the size before we do the copy, as we might overwrite the size field with the NULL - // terminator in the edge case where we are inserting enough characters to equal our capacity - const size_type nSavedSize = internalLayout().GetSize(); - CharStringUninitializedCopy((internalLayout().EndPtr() - n) + 1, internalLayout().EndPtr() + 1, internalLayout().EndPtr() + 1); - internalLayout().SetSize(nSavedSize + n); - memmove(const_cast<value_type*>(p) + n, p, (size_t)((nElementsAfter - n) + 1) * sizeof(value_type)); - memmove(const_cast<value_type*>(p), pBegin, (size_t)(n) * sizeof(value_type)); - } - else - { - pointer pOldEnd = internalLayout().EndPtr(); - #if EASTL_EXCEPTIONS_ENABLED - const size_type nOldSize = internalLayout().GetSize(); - #endif - const value_type* const pMid = pBegin + (nElementsAfter + 1); - - CharStringUninitializedCopy(pMid, pEnd, internalLayout().EndPtr() + 1); - internalLayout().SetSize(internalLayout().GetSize() + (n - nElementsAfter)); - - #if EASTL_EXCEPTIONS_ENABLED - try - { - #endif - // See comment in if block above - const size_type nSavedSize = internalLayout().GetSize(); - CharStringUninitializedCopy(p, pOldEnd + 1, internalLayout().EndPtr()); - internalLayout().SetSize(nSavedSize + nElementsAfter); - #if EASTL_EXCEPTIONS_ENABLED - } - catch(...) - { - internalLayout().SetSize(nOldSize); - throw; - } - #endif - - CharStringUninitializedCopy(pBegin, pMid, const_cast<value_type*>(p)); - } - } - else // Else we need to reallocate to implement this. - { - const size_type nOldSize = internalLayout().GetSize(); - const size_type nOldCap = capacity(); - size_type nLength; - - if(bCapacityIsSufficient) // If bCapacityIsSufficient is true, then bSourceIsFromSelf must be true. - nLength = nOldSize + n; - else - nLength = GetNewCapacity(nOldCap, (nOldSize + n) - nOldCap); - - pointer pNewBegin = DoAllocate(nLength + 1); - - pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); - pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, pNewEnd); - pNewEnd = CharStringUninitializedCopy(p, internalLayout().EndPtr(), pNewEnd); - *pNewEnd = 0; - - DeallocateSelf(); - internalLayout().SetHeapBeginPtr(pNewBegin); - internalLayout().SetHeapCapacity(nLength); - internalLayout().SetHeapSize(nOldSize + n); - } - } - - return internalLayout().BeginPtr() + nPosition; - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::insert(const_iterator p, std::initializer_list<value_type> ilist) - { - return insert(p, ilist.begin(), ilist.end()); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::erase(size_type position, size_type n) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - EASTL_FAIL_MSG("basic_string::erase -- invalid position"); - #endif - - erase(internalLayout().BeginPtr() + position, - internalLayout().BeginPtr() + position + eastl::min_alt(n, internalLayout().GetSize() - position)); - - return *this; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::erase(const_iterator p) - { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY((p < internalLayout().BeginPtr()) || (p >= internalLayout().EndPtr()))) - EASTL_FAIL_MSG("basic_string::erase -- invalid position"); - #endif - - memmove(const_cast<value_type*>(p), p + 1, (size_t)(internalLayout().EndPtr() - p) * sizeof(value_type)); - internalLayout().SetSize(internalLayout().GetSize() - 1); - return const_cast<value_type*>(p); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::erase(const_iterator pBegin, const_iterator pEnd) - { - #if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY((pBegin < internalLayout().BeginPtr()) || (pBegin > internalLayout().EndPtr()) || - (pEnd < internalLayout().BeginPtr()) || (pEnd > internalLayout().EndPtr()) || (pEnd < pBegin))) - EASTL_FAIL_MSG("basic_string::erase -- invalid position"); - #endif - - if(pBegin != pEnd) - { - memmove(const_cast<value_type*>(pBegin), pEnd, (size_t)((internalLayout().EndPtr() - pEnd) + 1) * sizeof(value_type)); - const size_type n = (size_type)(pEnd - pBegin); - internalLayout().SetSize(internalLayout().GetSize() - n); - } - return const_cast<value_type*>(pBegin); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::reverse_iterator - basic_string<T, Allocator>::erase(reverse_iterator position) - { - return reverse_iterator(erase((++position).base())); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::reverse_iterator - basic_string<T, Allocator>::erase(reverse_iterator first, reverse_iterator last) - { - return reverse_iterator(erase((++last).base(), (++first).base())); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::replace(size_type position, size_type n, const this_type& x) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - const size_type nLength = eastl::min_alt(n, internalLayout().GetSize() - position); - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY((internalLayout().GetSize() - nLength) >= (max_size() - x.internalLayout().GetSize()))) - ThrowLengthException(); - #endif - - return replace(internalLayout().BeginPtr() + position, internalLayout().BeginPtr() + position + nLength, x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::replace(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY((pos1 > internalLayout().GetSize()) || (pos2 > x.internalLayout().GetSize()))) - ThrowRangeException(); - #endif - - const size_type nLength1 = eastl::min_alt(n1, internalLayout().GetSize() - pos1); - const size_type nLength2 = eastl::min_alt(n2, x.internalLayout().GetSize() - pos2); - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY((internalLayout().GetSize() - nLength1) >= (max_size() - nLength2))) - ThrowLengthException(); - #endif - - return replace(internalLayout().BeginPtr() + pos1, internalLayout().BeginPtr() + pos1 + nLength1, x.internalLayout().BeginPtr() + pos2, x.internalLayout().BeginPtr() + pos2 + nLength2); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::replace(size_type position, size_type n1, const value_type* p, size_type n2) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - const size_type nLength = eastl::min_alt(n1, internalLayout().GetSize() - position); - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY((n2 > max_size()) || ((internalLayout().GetSize() - nLength) >= (max_size() - n2)))) - ThrowLengthException(); - #endif - - return replace(internalLayout().BeginPtr() + position, internalLayout().BeginPtr() + position + nLength, p, p + n2); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::replace(size_type position, size_type n1, const value_type* p) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - const size_type nLength = eastl::min_alt(n1, internalLayout().GetSize() - position); - - #if EASTL_STRING_OPT_LENGTH_ERRORS - const size_type n2 = (size_type)CharStrlen(p); - if(EASTL_UNLIKELY((n2 > max_size()) || ((internalLayout().GetSize() - nLength) >= (max_size() - n2)))) - ThrowLengthException(); - #endif - - return replace(internalLayout().BeginPtr() + position, internalLayout().BeginPtr() + position + nLength, p, p + CharStrlen(p)); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::replace(size_type position, size_type n1, size_type n2, value_type c) - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - const size_type nLength = eastl::min_alt(n1, internalLayout().GetSize() - position); - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY((n2 > max_size()) || (internalLayout().GetSize() - nLength) >= (max_size() - n2))) - ThrowLengthException(); - #endif - - return replace(internalLayout().BeginPtr() + position, internalLayout().BeginPtr() + position + nLength, n2, c); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::replace(const_iterator pBegin, const_iterator pEnd, const this_type& x) - { - return replace(pBegin, pEnd, x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::replace(const_iterator pBegin, const_iterator pEnd, const value_type* p, size_type n) - { - return replace(pBegin, pEnd, p, p + n); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::replace(const_iterator pBegin, const_iterator pEnd, const value_type* p) - { - return replace(pBegin, pEnd, p, p + CharStrlen(p)); - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::replace(const_iterator pBegin, const_iterator pEnd, size_type n, value_type c) - { - #if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY((pBegin < internalLayout().BeginPtr()) || (pBegin > internalLayout().EndPtr()) || - (pEnd < internalLayout().BeginPtr()) || (pEnd > internalLayout().EndPtr()) || (pEnd < pBegin))) - EASTL_FAIL_MSG("basic_string::replace -- invalid position"); - #endif - - const size_type nLength = static_cast<size_type>(pEnd - pBegin); - - if(nLength >= n) - { - CharTypeAssignN(const_cast<value_type*>(pBegin), n, c); - erase(pBegin + n, pEnd); - } - else - { - CharTypeAssignN(const_cast<value_type*>(pBegin), nLength, c); - insert(pEnd, n - nLength, c); - } - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::replace(const_iterator pBegin1, const_iterator pEnd1, const value_type* pBegin2, const value_type* pEnd2) - { - #if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY((pBegin1 < internalLayout().BeginPtr()) || (pBegin1 > internalLayout().EndPtr()) || - (pEnd1 < internalLayout().BeginPtr()) || (pEnd1 > internalLayout().EndPtr()) || (pEnd1 < pBegin1))) - EASTL_FAIL_MSG("basic_string::replace -- invalid position"); - #endif - - const size_type nLength1 = (size_type)(pEnd1 - pBegin1); - const size_type nLength2 = (size_type)(pEnd2 - pBegin2); - - if(nLength1 >= nLength2) // If we have a non-expanding operation... - { - if((pBegin2 > pEnd1) || (pEnd2 <= pBegin1)) // If we have a non-overlapping operation... - memcpy(const_cast<value_type*>(pBegin1), pBegin2, (size_t)(pEnd2 - pBegin2) * sizeof(value_type)); - else - memmove(const_cast<value_type*>(pBegin1), pBegin2, (size_t)(pEnd2 - pBegin2) * sizeof(value_type)); - erase(pBegin1 + nLength2, pEnd1); - } - else // Else we are expanding. - { - if((pBegin2 > pEnd1) || (pEnd2 <= pBegin1)) // If we have a non-overlapping operation... - { - const value_type* const pMid2 = pBegin2 + nLength1; - - if((pEnd2 <= pBegin1) || (pBegin2 > pEnd1)) - memcpy(const_cast<value_type*>(pBegin1), pBegin2, (size_t)(pMid2 - pBegin2) * sizeof(value_type)); - else - memmove(const_cast<value_type*>(pBegin1), pBegin2, (size_t)(pMid2 - pBegin2) * sizeof(value_type)); - insert(pEnd1, pMid2, pEnd2); - } - else // else we have an overlapping operation. - { - // I can't think of any easy way of doing this without allocating temporary memory. - const size_type nOldSize = internalLayout().GetSize(); - const size_type nOldCap = capacity(); - const size_type nNewCapacity = GetNewCapacity(nOldCap, (nOldSize + (nLength2 - nLength1)) - nOldCap); - - pointer pNewBegin = DoAllocate(nNewCapacity + 1); - - pointer pNewEnd = CharStringUninitializedCopy(internalLayout().BeginPtr(), pBegin1, pNewBegin); - pNewEnd = CharStringUninitializedCopy(pBegin2, pEnd2, pNewEnd); - pNewEnd = CharStringUninitializedCopy(pEnd1, internalLayout().EndPtr(), pNewEnd); - *pNewEnd = 0; - - DeallocateSelf(); - internalLayout().SetHeapBeginPtr(pNewBegin); - internalLayout().SetHeapCapacity(nNewCapacity); - internalLayout().SetHeapSize(nOldSize + (nLength2 - nLength1)); - } - } - return *this; - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::copy(value_type* p, size_type n, size_type position) const - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - // C++ std says the effects of this function are as if calling char_traits::copy() - // thus the 'p' must not overlap *this string, so we can use memcpy - const size_type nLength = eastl::min_alt(n, internalLayout().GetSize() - position); - CharStringUninitializedCopy(internalLayout().BeginPtr() + position, internalLayout().BeginPtr() + position + nLength, p); - return nLength; - } - - - template <typename T, typename Allocator> - void basic_string<T, Allocator>::swap(this_type& x) - { - if(get_allocator() == x.get_allocator() || (internalLayout().IsSSO() && x.internalLayout().IsSSO())) // If allocators are equivalent... - { - // We leave mAllocator as-is. - eastl::swap(internalLayout(), x.internalLayout()); - } - else // else swap the contents. - { - const this_type temp(*this); // Can't call eastl::swap because that would - *this = x; // itself call this member swap function. - x = temp; - } - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find(const this_type& x, size_type position) const EA_NOEXCEPT - { - return find(x.internalLayout().BeginPtr(), position, x.internalLayout().GetSize()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find(const value_type* p, size_type position) const - { - return find(p, position, (size_type)CharStrlen(p)); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find(const value_type* p, size_type position, size_type n) const - { - // It is not clear what the requirements are for position, but since the C++ standard - // appears to be silent it is assumed for now that position can be any value. - //#if EASTL_ASSERT_ENABLED - // if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) - // EASTL_FAIL_MSG("basic_string::find -- invalid position"); - //#endif - - if(EASTL_LIKELY(((npos - n) >= position) && (position + n) <= internalLayout().GetSize())) // If the range is valid... - { - const value_type* const pTemp = eastl::search(internalLayout().BeginPtr() + position, internalLayout().EndPtr(), p, p + n); - - if((pTemp != internalLayout().EndPtr()) || (n == 0)) - return (size_type)(pTemp - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find(value_type c, size_type position) const EA_NOEXCEPT - { - // It is not clear what the requirements are for position, but since the C++ standard - // appears to be silent it is assumed for now that position can be any value. - //#if EASTL_ASSERT_ENABLED - // if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) - // EASTL_FAIL_MSG("basic_string::find -- invalid position"); - //#endif - - if(EASTL_LIKELY(position < internalLayout().GetSize()))// If the position is valid... - { - const const_iterator pResult = eastl::find(internalLayout().BeginPtr() + position, internalLayout().EndPtr(), c); - - if(pResult != internalLayout().EndPtr()) - return (size_type)(pResult - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::rfind(const this_type& x, size_type position) const EA_NOEXCEPT - { - return rfind(x.internalLayout().BeginPtr(), position, x.internalLayout().GetSize()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::rfind(const value_type* p, size_type position) const - { - return rfind(p, position, (size_type)CharStrlen(p)); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::rfind(const value_type* p, size_type position, 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. - const size_type nLength = internalLayout().GetSize(); - - if(EASTL_LIKELY(n <= nLength)) - { - if(EASTL_LIKELY(n)) - { - const const_iterator pEnd = internalLayout().BeginPtr() + eastl::min_alt(nLength - n, position) + n; - const const_iterator pResult = CharTypeStringRSearch(internalLayout().BeginPtr(), pEnd, p, p + n); - - if(pResult != pEnd) - return (size_type)(pResult - internalLayout().BeginPtr()); - } - else - return eastl::min_alt(nLength, position); - } - return npos; - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::rfind(value_type c, size_type position) const EA_NOEXCEPT - { - // If n is zero or position is >= size, we return npos. - const size_type nLength = internalLayout().GetSize(); - - if(EASTL_LIKELY(nLength)) - { - const value_type* const pEnd = internalLayout().BeginPtr() + eastl::min_alt(nLength - 1, position) + 1; - const value_type* const pResult = CharTypeStringRFind(pEnd, internalLayout().BeginPtr(), c); - - if(pResult != internalLayout().BeginPtr()) - return (size_type)((pResult - 1) - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_first_of(const this_type& x, size_type position) const EA_NOEXCEPT - { - return find_first_of(x.internalLayout().BeginPtr(), position, x.internalLayout().GetSize()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_first_of(const value_type* p, size_type position) const - { - return find_first_of(p, position, (size_type)CharStrlen(p)); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_first_of(const value_type* p, size_type position, size_type n) const - { - // If position is >= size, we return npos. - if(EASTL_LIKELY((position < internalLayout().GetSize()))) - { - const value_type* const pBegin = internalLayout().BeginPtr() + position; - const const_iterator pResult = CharTypeStringFindFirstOf(pBegin, internalLayout().EndPtr(), p, p + n); - - if(pResult != internalLayout().EndPtr()) - return (size_type)(pResult - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_first_of(value_type c, size_type position) const EA_NOEXCEPT - { - return find(c, position); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_last_of(const this_type& x, size_type position) const EA_NOEXCEPT - { - return find_last_of(x.internalLayout().BeginPtr(), position, x.internalLayout().GetSize()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_last_of(const value_type* p, size_type position) const - { - return find_last_of(p, position, (size_type)CharStrlen(p)); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_last_of(const value_type* p, size_type position, size_type n) const - { - // If n is zero or position is >= size, we return npos. - const size_type nLength = internalLayout().GetSize(); - - if(EASTL_LIKELY(nLength)) - { - const value_type* const pEnd = internalLayout().BeginPtr() + eastl::min_alt(nLength - 1, position) + 1; - const value_type* const pResult = CharTypeStringRFindFirstOf(pEnd, internalLayout().BeginPtr(), p, p + n); - - if(pResult != internalLayout().BeginPtr()) - return (size_type)((pResult - 1) - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_last_of(value_type c, size_type position) const EA_NOEXCEPT - { - return rfind(c, position); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_first_not_of(const this_type& x, size_type position) const EA_NOEXCEPT - { - return find_first_not_of(x.internalLayout().BeginPtr(), position, x.internalLayout().GetSize()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_first_not_of(const value_type* p, size_type position) const - { - return find_first_not_of(p, position, (size_type)CharStrlen(p)); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_first_not_of(const value_type* p, size_type position, size_type n) const - { - if(EASTL_LIKELY(position <= internalLayout().GetSize())) - { - const const_iterator pResult = - CharTypeStringFindFirstNotOf(internalLayout().BeginPtr() + position, internalLayout().EndPtr(), p, p + n); - - if(pResult != internalLayout().EndPtr()) - return (size_type)(pResult - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_first_not_of(value_type c, size_type position) const EA_NOEXCEPT - { - if(EASTL_LIKELY(position <= internalLayout().GetSize())) - { - // Todo: Possibly make a specialized version of CharTypeStringFindFirstNotOf(pBegin, pEnd, c). - const const_iterator pResult = - CharTypeStringFindFirstNotOf(internalLayout().BeginPtr() + position, internalLayout().EndPtr(), &c, &c + 1); - - if(pResult != internalLayout().EndPtr()) - return (size_type)(pResult - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_last_not_of(const this_type& x, size_type position) const EA_NOEXCEPT - { - return find_last_not_of(x.internalLayout().BeginPtr(), position, x.internalLayout().GetSize()); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_last_not_of(const value_type* p, size_type position) const - { - return find_last_not_of(p, position, (size_type)CharStrlen(p)); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_last_not_of(const value_type* p, size_type position, size_type n) const - { - const size_type nLength = internalLayout().GetSize(); - - if(EASTL_LIKELY(nLength)) - { - const value_type* const pEnd = internalLayout().BeginPtr() + eastl::min_alt(nLength - 1, position) + 1; - const value_type* const pResult = CharTypeStringRFindFirstNotOf(pEnd, internalLayout().BeginPtr(), p, p + n); - - if(pResult != internalLayout().BeginPtr()) - return (size_type)((pResult - 1) - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::find_last_not_of(value_type c, size_type position) const EA_NOEXCEPT - { - const size_type nLength = internalLayout().GetSize(); - - if(EASTL_LIKELY(nLength)) - { - // Todo: Possibly make a specialized version of CharTypeStringRFindFirstNotOf(pBegin, pEnd, c). - const value_type* const pEnd = internalLayout().BeginPtr() + eastl::min_alt(nLength - 1, position) + 1; - const value_type* const pResult = CharTypeStringRFindFirstNotOf(pEnd, internalLayout().BeginPtr(), &c, &c + 1); - - if(pResult != internalLayout().BeginPtr()) - return (size_type)((pResult - 1) - internalLayout().BeginPtr()); - } - return npos; - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator> basic_string<T, Allocator>::substr(size_type position, size_type n) const - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - ThrowRangeException(); - #elif EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(position > internalLayout().GetSize())) - EASTL_FAIL_MSG("basic_string::substr -- invalid position"); - #endif - - // C++ std says the return string allocator must be default constructed, not a copy of this->get_allocator() - return basic_string( - internalLayout().BeginPtr() + position, - internalLayout().BeginPtr() + position + - eastl::min_alt(n, internalLayout().GetSize() - position), get_allocator()); - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::compare(const this_type& x) const EA_NOEXCEPT - { - return compare(internalLayout().BeginPtr(), internalLayout().EndPtr(), x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::compare(size_type pos1, size_type n1, const this_type& x) const - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(pos1 > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - return compare( - internalLayout().BeginPtr() + pos1, - internalLayout().BeginPtr() + pos1 + eastl::min_alt(n1, internalLayout().GetSize() - pos1), - x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::compare(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2) const - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY((pos1 > (size_type)(internalLayout().EndPtr() - internalLayout().BeginPtr())) || - (pos2 > (size_type)(x.internalLayout().EndPtr() - x.internalLayout().BeginPtr())))) - ThrowRangeException(); - #endif - - return compare(internalLayout().BeginPtr() + pos1, - internalLayout().BeginPtr() + pos1 + eastl::min_alt(n1, internalLayout().GetSize() - pos1), - x.internalLayout().BeginPtr() + pos2, - x.internalLayout().BeginPtr() + pos2 + eastl::min_alt(n2, x.internalLayout().GetSize() - pos2)); - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::compare(const value_type* p) const - { - return compare(internalLayout().BeginPtr(), internalLayout().EndPtr(), p, p + CharStrlen(p)); - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::compare(size_type pos1, size_type n1, const value_type* p) const - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(pos1 > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - return compare(internalLayout().BeginPtr() + pos1, - internalLayout().BeginPtr() + pos1 + eastl::min_alt(n1, internalLayout().GetSize() - pos1), - p, - p + CharStrlen(p)); - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::compare(size_type pos1, size_type n1, const value_type* p, size_type n2) const - { - #if EASTL_STRING_OPT_RANGE_ERRORS - if(EASTL_UNLIKELY(pos1 > internalLayout().GetSize())) - ThrowRangeException(); - #endif - - return compare(internalLayout().BeginPtr() + pos1, - internalLayout().BeginPtr() + pos1 + eastl::min_alt(n1, internalLayout().GetSize() - pos1), - p, - p + n2); - } - - - // make_lower - // This is a very simple ASCII-only case conversion function - // Anything more complicated should use a more powerful separate library. - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::make_lower() - { - for(pointer p = internalLayout().BeginPtr(); p < internalLayout().EndPtr(); ++p) - *p = (value_type)CharToLower(*p); - } - - - // make_upper - // This is a very simple ASCII-only case conversion function - // Anything more complicated should use a more powerful separate library. - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::make_upper() - { - for(pointer p = internalLayout().BeginPtr(); p < internalLayout().EndPtr(); ++p) - *p = (value_type)CharToUpper(*p); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::ltrim() - { - const value_type array[] = { ' ', '\t', 0 }; // This is a pretty simplistic view of whitespace. - erase(0, find_first_not_of(array)); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::rtrim() - { - const value_type array[] = { ' ', '\t', 0 }; // This is a pretty simplistic view of whitespace. - erase(find_last_not_of(array) + 1); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::trim() - { - ltrim(); - rtrim(); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::ltrim(const value_type* p) - { - erase(0, find_first_not_of(p)); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::rtrim(const value_type* p) - { - erase(find_last_not_of(p) + 1); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::trim(const value_type* p) - { - ltrim(p); - rtrim(p); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator> basic_string<T, Allocator>::left(size_type n) const - { - const size_type nLength = length(); - if(n < nLength) - return substr(0, n); - // C++ std says that substr must return default constructed allocated, but we do not. - // Instead it is much more practical to provide the copy of the current allocator - return basic_string(*this, get_allocator()); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator> basic_string<T, Allocator>::right(size_type n) const - { - const size_type nLength = length(); - if(n < nLength) - return substr(nLength - n, n); - // C++ std says that substr must return default constructed allocated, but we do not. - // Instead it is much more practical to provide the copy of the current allocator - return basic_string(*this, get_allocator()); - } - - - template <typename T, typename Allocator> - inline basic_string<T, Allocator>& basic_string<T, Allocator>::sprintf(const value_type* pFormat, ...) - { - va_list arguments; - va_start(arguments, pFormat); - internalLayout().SetSize(0); // Fast truncate to zero length. - append_sprintf_va_list(pFormat, arguments); - va_end(arguments); - - return *this; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator>& basic_string<T, Allocator>::sprintf_va_list(const value_type* pFormat, va_list arguments) - { - internalLayout().SetSize(0); // Fast truncate to zero length. - - return append_sprintf_va_list(pFormat, arguments); - } - - - template <typename T, typename Allocator> - int basic_string<T, Allocator>::compare(const value_type* pBegin1, const value_type* pEnd1, - const value_type* pBegin2, const value_type* pEnd2) - { - const difference_type n1 = pEnd1 - pBegin1; - const difference_type n2 = pEnd2 - pBegin2; - const difference_type nMin = eastl::min_alt(n1, n2); - const int cmp = Compare(pBegin1, pBegin2, (size_t)nMin); - - return (cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0))); - } - - - template <typename T, typename Allocator> - int basic_string<T, Allocator>::comparei(const value_type* pBegin1, const value_type* pEnd1, - const value_type* pBegin2, const value_type* pEnd2) - { - const difference_type n1 = pEnd1 - pBegin1; - const difference_type n2 = pEnd2 - pBegin2; - const difference_type nMin = eastl::min_alt(n1, n2); - const int cmp = CompareI(pBegin1, pBegin2, (size_t)nMin); - - return (cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0))); - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::comparei(const this_type& x) const EA_NOEXCEPT - { - return comparei(internalLayout().BeginPtr(), internalLayout().EndPtr(), x.internalLayout().BeginPtr(), x.internalLayout().EndPtr()); - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::comparei(const value_type* p) const - { - return comparei(internalLayout().BeginPtr(), internalLayout().EndPtr(), p, p + CharStrlen(p)); - } - - - template <typename T, typename Allocator> - typename basic_string<T, Allocator>::iterator - basic_string<T, Allocator>::InsertInternal(const_iterator p, value_type c) - { - iterator pNewPosition = const_cast<value_type*>(p); - - if((internalLayout().EndPtr() + 1) <= internalLayout().CapacityPtr()) - { - const size_type nSavedSize = internalLayout().GetSize(); - memmove(const_cast<value_type*>(p) + 1, p, (size_t)(internalLayout().EndPtr() - p) * sizeof(value_type)); - *(internalLayout().EndPtr() + 1) = 0; - *pNewPosition = c; - internalLayout().SetSize(nSavedSize + 1); - } - else - { - const size_type nOldSize = internalLayout().GetSize(); - const size_type nOldCap = capacity(); - const size_type nLength = GetNewCapacity(nOldCap, 1); - - iterator pNewBegin = DoAllocate(nLength + 1); - - pNewPosition = CharStringUninitializedCopy(internalLayout().BeginPtr(), p, pNewBegin); - *pNewPosition = c; - - iterator pNewEnd = pNewPosition + 1; - pNewEnd = CharStringUninitializedCopy(p, internalLayout().EndPtr(), pNewEnd); - *pNewEnd = 0; - - DeallocateSelf(); - internalLayout().SetHeapBeginPtr(pNewBegin); - internalLayout().SetHeapCapacity(nLength); - internalLayout().SetHeapSize(nOldSize + 1); - } - return pNewPosition; - } - - - template <typename T, typename Allocator> - void basic_string<T, Allocator>::SizeInitialize(size_type n, value_type c) - { - AllocateSelf(n); - - CharStringUninitializedFillN(internalLayout().BeginPtr(), n, c); - *internalLayout().EndPtr() = 0; - } - - - template <typename T, typename Allocator> - void basic_string<T, Allocator>::RangeInitialize(const value_type* pBegin, const value_type* pEnd) - { - #if EASTL_STRING_OPT_ARGUMENT_ERRORS - if(EASTL_UNLIKELY(!pBegin && (pEnd < pBegin))) // 21.4.2 p7 - ThrowInvalidArgumentException(); - #endif - - const size_type n = (size_type)(pEnd - pBegin); - - AllocateSelf(n); - - CharStringUninitializedCopy(pBegin, pEnd, internalLayout().BeginPtr()); - *internalLayout().EndPtr() = 0; - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::RangeInitialize(const value_type* pBegin) - { - #if EASTL_STRING_OPT_ARGUMENT_ERRORS - if(EASTL_UNLIKELY(!pBegin)) - ThrowInvalidArgumentException(); - #endif - - RangeInitialize(pBegin, pBegin + CharStrlen(pBegin)); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::DoAllocate(size_type n) - { - return (value_type*)EASTLAlloc(get_allocator(), n * sizeof(value_type)); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::DoFree(value_type* p, size_type n) - { - if(p) - EASTLFree(get_allocator(), p, n * sizeof(value_type)); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::GetNewCapacity(size_type currentCapacity) - { - return GetNewCapacity(currentCapacity, 1); - } - - - template <typename T, typename Allocator> - inline typename basic_string<T, Allocator>::size_type - basic_string<T, Allocator>::GetNewCapacity(size_type currentCapacity, size_type minimumGrowSize) - { - #if EASTL_STRING_OPT_LENGTH_ERRORS - const size_type nRemainingSize = max_size() - currentCapacity; - if(EASTL_UNLIKELY((minimumGrowSize > nRemainingSize))) - { - ThrowLengthException(); - } - #endif - - const size_type nNewCapacity = eastl::max_alt(currentCapacity + minimumGrowSize, currentCapacity * 2); - - return nNewCapacity; - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::AllocateSelf() - { - internalLayout().ResetToSSO(); - } - - - template <typename T, typename Allocator> - void basic_string<T, Allocator>::AllocateSelf(size_type n) - { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(n >= 0x40000000)) - EASTL_FAIL_MSG("basic_string::AllocateSelf -- improbably large request."); - #endif - - #if EASTL_STRING_OPT_LENGTH_ERRORS - if(EASTL_UNLIKELY(n > max_size())) - ThrowLengthException(); - #endif - - if(n > SSOLayout::SSO_CAPACITY) - { - pointer pBegin = DoAllocate(n + 1); - internalLayout().SetHeapBeginPtr(pBegin); - internalLayout().SetHeapCapacity(n); - internalLayout().SetHeapSize(n); - } - else - internalLayout().SetSSOSize(n); - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::DeallocateSelf() - { - if(internalLayout().IsHeap()) - { - DoFree(internalLayout().BeginPtr(), internalLayout().GetHeapCapacity() + 1); - } - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::ThrowLengthException() const - { - #if EASTL_EXCEPTIONS_ENABLED - throw std::length_error("basic_string -- length_error"); - #elif EASTL_ASSERT_ENABLED - EASTL_FAIL_MSG("basic_string -- length_error"); - #endif - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::ThrowRangeException() const - { - #if EASTL_EXCEPTIONS_ENABLED - throw std::out_of_range("basic_string -- out of range"); - #elif EASTL_ASSERT_ENABLED - EASTL_FAIL_MSG("basic_string -- out of range"); - #endif - } - - - template <typename T, typename Allocator> - inline void basic_string<T, Allocator>::ThrowInvalidArgumentException() const - { - #if EASTL_EXCEPTIONS_ENABLED - throw std::invalid_argument("basic_string -- invalid argument"); - #elif EASTL_ASSERT_ENABLED - EASTL_FAIL_MSG("basic_string -- invalid argument"); - #endif - } - - - // CharTypeStringFindEnd - // Specialized char version of STL find() from back function. - // Not the same as RFind because search range is specified as forward iterators. - template <typename T, typename Allocator> - const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::CharTypeStringFindEnd(const value_type* pBegin, const value_type* pEnd, value_type c) - { - const value_type* pTemp = pEnd; - while(--pTemp >= pBegin) - { - if(*pTemp == c) - return pTemp; - } - - return pEnd; - } - - - // CharTypeStringRFind - // Specialized value_type version of STL find() function in reverse. - template <typename T, typename Allocator> - const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::CharTypeStringRFind(const value_type* pRBegin, const value_type* pREnd, const value_type c) - { - while(pRBegin > pREnd) - { - if(*(pRBegin - 1) == c) - return pRBegin; - --pRBegin; - } - return pREnd; - } - - - // CharTypeStringSearch - // Specialized value_type version of STL search() function. - // Purpose: find p2 within p1. Return p1End if not found or if either string is zero length. - template <typename T, typename Allocator> - const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::CharTypeStringSearch(const value_type* p1Begin, const value_type* p1End, - const value_type* p2Begin, const value_type* p2End) - { - // Test for zero length strings, in which case we have a match or a failure, - // but the return value is the same either way. - if((p1Begin == p1End) || (p2Begin == p2End)) - return p1Begin; - - // Test for a pattern of length 1. - if((p2Begin + 1) == p2End) - return eastl::find(p1Begin, p1End, *p2Begin); - - // General case. - const value_type* pTemp; - const value_type* pTemp1 = (p2Begin + 1); - const value_type* pCurrent = p1Begin; - - while(p1Begin != p1End) - { - p1Begin = eastl::find(p1Begin, p1End, *p2Begin); - if(p1Begin == p1End) - return p1End; - - pTemp = pTemp1; - pCurrent = p1Begin; - if(++pCurrent == p1End) - return p1End; - - while(*pCurrent == *pTemp) - { - if(++pTemp == p2End) - return p1Begin; - if(++pCurrent == p1End) - return p1End; - } - - ++p1Begin; - } - - return p1Begin; - } - - - // CharTypeStringRSearch - // Specialized value_type version of STL find_end() function (which really is a reverse search function). - // Purpose: find last instance of p2 within p1. Return p1End if not found or if either string is zero length. - template <typename T, typename Allocator> - const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::CharTypeStringRSearch(const value_type* p1Begin, const value_type* p1End, - const value_type* p2Begin, const value_type* p2End) - { - // Test for zero length strings, in which case we have a match or a failure, - // but the return value is the same either way. - if((p1Begin == p1End) || (p2Begin == p2End)) - return p1Begin; - - // Test for a pattern of length 1. - if((p2Begin + 1) == p2End) - return CharTypeStringFindEnd(p1Begin, p1End, *p2Begin); - - // Test for search string length being longer than string length. - if((p2End - p2Begin) > (p1End - p1Begin)) - return p1End; - - // General case. - const value_type* pSearchEnd = (p1End - (p2End - p2Begin) + 1); - const value_type* pCurrent1; - const value_type* pCurrent2; - - while(pSearchEnd != p1Begin) - { - // Search for the last occurrence of *p2Begin. - pCurrent1 = CharTypeStringFindEnd(p1Begin, pSearchEnd, *p2Begin); - if(pCurrent1 == pSearchEnd) // If the first char of p2 wasn't found, - return p1End; // then we immediately have failure. - - // In this case, *pTemp == *p2Begin. So compare the rest. - pCurrent2 = p2Begin; - while(*pCurrent1++ == *pCurrent2++) - { - if(pCurrent2 == p2End) - return (pCurrent1 - (p2End - p2Begin)); - } - - // A smarter algorithm might know to subtract more than just one, - // but in most cases it won't make much difference anyway. - --pSearchEnd; - } - - return p1End; - } - - - // CharTypeStringFindFirstOf - // Specialized value_type version of STL find_first_of() function. - // This function is much like the C runtime strtok function, except the strings aren't null-terminated. - template <typename T, typename Allocator> - const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::CharTypeStringFindFirstOf(const value_type* p1Begin, const value_type* p1End, - const value_type* p2Begin, const value_type* p2End) - { - for( ; p1Begin != p1End; ++p1Begin) - { - for(const value_type* pTemp = p2Begin; pTemp != p2End; ++pTemp) - { - if(*p1Begin == *pTemp) - return p1Begin; - } - } - return p1End; - } - - - // CharTypeStringRFindFirstOf - // Specialized value_type version of STL find_first_of() function in reverse. - // This function is much like the C runtime strtok function, except the strings aren't null-terminated. - template <typename T, typename Allocator> - const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::CharTypeStringRFindFirstOf(const value_type* p1RBegin, const value_type* p1REnd, - const value_type* p2Begin, const value_type* p2End) - { - for( ; p1RBegin != p1REnd; --p1RBegin) - { - for(const value_type* pTemp = p2Begin; pTemp != p2End; ++pTemp) - { - if(*(p1RBegin - 1) == *pTemp) - return p1RBegin; - } - } - return p1REnd; - } - - - - // CharTypeStringFindFirstNotOf - // Specialized value_type version of STL find_first_not_of() function. - template <typename T, typename Allocator> - const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::CharTypeStringFindFirstNotOf(const value_type* p1Begin, const value_type* p1End, - const value_type* p2Begin, const value_type* p2End) - { - for( ; p1Begin != p1End; ++p1Begin) - { - const value_type* pTemp; - for(pTemp = p2Begin; pTemp != p2End; ++pTemp) - { - if(*p1Begin == *pTemp) - break; - } - if(pTemp == p2End) - return p1Begin; - } - return p1End; - } - - - // CharTypeStringRFindFirstNotOf - // Specialized value_type version of STL find_first_not_of() function in reverse. - template <typename T, typename Allocator> - const typename basic_string<T, Allocator>::value_type* - basic_string<T, Allocator>::CharTypeStringRFindFirstNotOf(const value_type* p1RBegin, const value_type* p1REnd, - const value_type* p2Begin, const value_type* p2End) - { - for( ; p1RBegin != p1REnd; --p1RBegin) - { - const value_type* pTemp; - for(pTemp = p2Begin; pTemp != p2End; ++pTemp) - { - if(*(p1RBegin-1) == *pTemp) - break; - } - if(pTemp == p2End) - return p1RBegin; - } - return p1REnd; - } - - - - - // iterator operators - template <typename T, typename Allocator> - inline bool operator==(const typename basic_string<T, Allocator>::reverse_iterator& r1, - const typename basic_string<T, Allocator>::reverse_iterator& r2) - { - return r1.mpCurrent == r2.mpCurrent; - } - - - template <typename T, typename Allocator> - inline bool operator!=(const typename basic_string<T, Allocator>::reverse_iterator& r1, - const typename basic_string<T, Allocator>::reverse_iterator& r2) - { - return r1.mpCurrent != r2.mpCurrent; - } - - - // Operator + - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b) - { - typedef typename basic_string<T, Allocator>::CtorDoNotInitialize CtorDoNotInitialize; - CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. - basic_string<T, Allocator> result(cDNI, a.size() + b.size(), const_cast<basic_string<T, Allocator>&>(a).get_allocator()); // Note that we choose to assign a's allocator. - result.append(a); - result.append(b); - return result; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b) - { - typedef typename basic_string<T, Allocator>::CtorDoNotInitialize CtorDoNotInitialize; - CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. - const typename basic_string<T, Allocator>::size_type n = (typename basic_string<T, Allocator>::size_type)CharStrlen(p); - basic_string<T, Allocator> result(cDNI, n + b.size(), const_cast<basic_string<T, Allocator>&>(b).get_allocator()); - result.append(p, p + n); - result.append(b); - return result; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(typename basic_string<T, Allocator>::value_type c, const basic_string<T, Allocator>& b) - { - typedef typename basic_string<T, Allocator>::CtorDoNotInitialize CtorDoNotInitialize; - CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. - basic_string<T, Allocator> result(cDNI, 1 + b.size(), const_cast<basic_string<T, Allocator>&>(b).get_allocator()); - result.push_back(c); - result.append(b); - return result; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p) - { - typedef typename basic_string<T, Allocator>::CtorDoNotInitialize CtorDoNotInitialize; - CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. - const typename basic_string<T, Allocator>::size_type n = (typename basic_string<T, Allocator>::size_type)CharStrlen(p); - basic_string<T, Allocator> result(cDNI, a.size() + n, const_cast<basic_string<T, Allocator>&>(a).get_allocator()); - result.append(a); - result.append(p, p + n); - return result; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(const basic_string<T, Allocator>& a, typename basic_string<T, Allocator>::value_type c) - { - typedef typename basic_string<T, Allocator>::CtorDoNotInitialize CtorDoNotInitialize; - CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. - basic_string<T, Allocator> result(cDNI, a.size() + 1, const_cast<basic_string<T, Allocator>&>(a).get_allocator()); - result.append(a); - result.push_back(c); - return result; - } - - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(basic_string<T, Allocator>&& a, basic_string<T, Allocator>&& b) - { - a.append(b); // Using an rvalue by name results in it becoming an lvalue. - return eastl::move(a); - } - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(basic_string<T, Allocator>&& a, const basic_string<T, Allocator>& b) - { - a.append(b); - return eastl::move(a); - } - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(const typename basic_string<T, Allocator>::value_type* p, basic_string<T, Allocator>&& b) - { - b.insert(0, p); - return eastl::move(b); - } - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(basic_string<T, Allocator>&& a, const typename basic_string<T, Allocator>::value_type* p) - { - a.append(p); - return eastl::move(a); - } - - template <typename T, typename Allocator> - basic_string<T, Allocator> operator+(basic_string<T, Allocator>&& a, typename basic_string<T, Allocator>::value_type c) - { - a.push_back(c); - return eastl::move(a); - } - - - template <typename T, typename Allocator> - inline bool basic_string<T, Allocator>::validate() const EA_NOEXCEPT - { - if((internalLayout().BeginPtr() == nullptr) || (internalLayout().EndPtr() == nullptr)) - return false; - if(internalLayout().EndPtr() < internalLayout().BeginPtr()) - return false; - if(internalLayout().CapacityPtr() < internalLayout().EndPtr()) - return false; - if(*internalLayout().EndPtr() != 0) - return false; - return true; - } - - - template <typename T, typename Allocator> - inline int basic_string<T, Allocator>::validate_iterator(const_iterator i) const EA_NOEXCEPT - { - if(i >= internalLayout().BeginPtr()) - { - if(i < internalLayout().EndPtr()) - return (isf_valid | isf_current | isf_can_dereference); - - if(i <= internalLayout().EndPtr()) - return (isf_valid | isf_current); - } - - return isf_none; - } - - - /////////////////////////////////////////////////////////////////////// - // global operators - /////////////////////////////////////////////////////////////////////// - - // Operator== and operator!= - template <typename T, typename Allocator> - inline bool operator==(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b) - { - return ((a.size() == b.size()) && (memcmp(a.data(), b.data(), (size_t)a.size() * sizeof(typename basic_string<T, Allocator>::value_type)) == 0)); - } - -#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) - template <typename T, typename Allocator> - inline bool operator==(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b) - { - typedef typename basic_string<T, Allocator>::size_type size_type; - const size_type n = (size_type)CharStrlen(p); - return ((n == b.size()) && (memcmp(p, b.data(), (size_t)n * sizeof(*p)) == 0)); - } -#endif - - template <typename T, typename Allocator> - inline bool operator==(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p) - { - typedef typename basic_string<T, Allocator>::size_type size_type; - const size_type n = (size_type)CharStrlen(p); - return ((a.size() == n) && (memcmp(a.data(), p, (size_t)n * sizeof(*p)) == 0)); - } - -#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) - template <typename T, typename Allocator> - inline auto operator<=>(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b) - { - return basic_string<T, Allocator>::compare(a.begin(), a.end(), b.begin(), b.end()) <=> 0; - } - - template <typename T, typename Allocator> - inline auto operator<=>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p) - { - typedef typename basic_string<T, Allocator>::size_type size_type; - const size_type n = (size_type)CharStrlen(p); - return basic_string<T, Allocator>::compare(a.begin(), a.end(), p, p + n) <=> 0; - } - - template <typename T, typename Allocator> - inline auto operator<=>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v) - { - typedef typename basic_string<T, Allocator>::view_type view_type; - return static_cast<view_type>(a) <=> v; - } - -#else - - template <typename T, typename Allocator> - inline bool operator==(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - typedef typename basic_string<T, Allocator>::view_type view_type; - return v == static_cast<view_type>(b); - } - - template <typename T, typename Allocator> - inline bool operator==(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - typedef typename basic_string<T, Allocator>::view_type view_type; - return static_cast<view_type>(a) == v; - } - - - template <typename T, typename Allocator> - inline bool operator!=(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b) - { - return !(a == b); - } - - template <typename T, typename Allocator> - inline bool operator!=(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b) - { - return !(p == b); - } - - - template <typename T, typename Allocator> - inline bool operator!=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p) - { - return !(a == p); - } - - - template <typename T, typename Allocator> - inline bool operator!=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - return !(v == b); - } - - - template <typename T, typename Allocator> - inline bool operator!=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - return !(a == v); - } - - - // Operator< (and also >, <=, and >=). - template <typename T, typename Allocator> - inline bool operator<(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b) - { - return basic_string<T, Allocator>::compare(a.begin(), a.end(), b.begin(), b.end()) < 0; } - - - template <typename T, typename Allocator> - inline bool operator<(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b) - { - typedef typename basic_string<T, Allocator>::size_type size_type; - const size_type n = (size_type)CharStrlen(p); - return basic_string<T, Allocator>::compare(p, p + n, b.begin(), b.end()) < 0; - } - - - template <typename T, typename Allocator> - inline bool operator<(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p) - { - typedef typename basic_string<T, Allocator>::size_type size_type; - const size_type n = (size_type)CharStrlen(p); - return basic_string<T, Allocator>::compare(a.begin(), a.end(), p, p + n) < 0; - } - - - template <typename T, typename Allocator> - inline bool operator<(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - typedef typename basic_string<T, Allocator>::view_type view_type; - return v < static_cast<view_type>(b); - } - - - template <typename T, typename Allocator> - inline bool operator<(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - typedef typename basic_string<T, Allocator>::view_type view_type; - return static_cast<view_type>(a) < v; - } - - - template <typename T, typename Allocator> - inline bool operator>(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b) - { - return b < a; - } - - - template <typename T, typename Allocator> - inline bool operator>(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b) - { - return b < p; - } - - - template <typename T, typename Allocator> - inline bool operator>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p) - { - return p < a; - } - - - template <typename T, typename Allocator> - inline bool operator>(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - return b < v; - } - - - template <typename T, typename Allocator> - inline bool operator>(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - return v < a; - } - - - template <typename T, typename Allocator> - inline bool operator<=(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b) - { - return !(b < a); - } - - - template <typename T, typename Allocator> - inline bool operator<=(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b) - { - return !(b < p); - } - - - template <typename T, typename Allocator> - inline bool operator<=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p) - { - return !(p < a); - } - - - template <typename T, typename Allocator> - inline bool operator<=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - return !(b < v); - } - - - template <typename T, typename Allocator> - inline bool operator<=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - return !(v < a); - } - - - template <typename T, typename Allocator> - inline bool operator>=(const basic_string<T, Allocator>& a, const basic_string<T, Allocator>& b) - { - return !(a < b); - } - - - template <typename T, typename Allocator> - inline bool operator>=(const typename basic_string<T, Allocator>::value_type* p, const basic_string<T, Allocator>& b) - { - return !(p < b); - } - - - template <typename T, typename Allocator> - inline bool operator>=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::value_type* p) - { - return !(a < p); - } - - - template <typename T, typename Allocator> - inline bool operator>=(const typename basic_string<T, Allocator>::view_type v, const basic_string<T, Allocator>& b) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - return !(v < b); - } - - - template <typename T, typename Allocator> - inline bool operator>=(const basic_string<T, Allocator>& a, const typename basic_string<T, Allocator>::view_type v) - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - return !(a < v); - } -#endif - - template <typename T, typename Allocator> - inline void swap(basic_string<T, Allocator>& a, basic_string<T, Allocator>& b) - { - a.swap(b); - } - - - /// string / wstring - typedef basic_string<char> string; - typedef basic_string<wchar_t> wstring; - - /// custom string8 / string16 / string32 - typedef basic_string<char> string8; - typedef basic_string<char16_t> string16; - typedef basic_string<char32_t> string32; - - /// ISO mandated string types - typedef basic_string<char8_t> u8string; // Actually not a C++11 type, but added for consistency. - typedef basic_string<char16_t> u16string; - typedef basic_string<char32_t> u32string; - - - /// hash<string> - /// - /// We provide EASTL hash function objects for use in hash table containers. - /// - /// Example usage: - /// #include <EASTL/hash_set.h> - /// hash_set<string> stringHashSet; - /// - template <typename T> struct hash; - - template <> - struct hash<string> - { - size_t operator()(const string& x) const - { - const unsigned char* p = (const unsigned char*)x.c_str(); // 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; - } - }; - - #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE - template <> - struct hash<u8string> - { - size_t operator()(const u8string& x) const - { - const char8_t* p = (const char8_t*)x.c_str(); - unsigned int c, result = 2166136261U; - while((c = *p++) != 0) - result = (result * 16777619) ^ c; - return (size_t)result; - } - }; - #endif - - template <> - struct hash<string16> - { - size_t operator()(const string16& x) const - { - const char16_t* p = x.c_str(); - unsigned int c, result = 2166136261U; - while((c = *p++) != 0) - result = (result * 16777619) ^ c; - return (size_t)result; - } - }; - - template <> - struct hash<string32> - { - size_t operator()(const string32& x) const - { - const char32_t* p = x.c_str(); - 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<wstring> - { - size_t operator()(const wstring& x) const - { - const wchar_t* p = x.c_str(); - unsigned int c, result = 2166136261U; - while((c = (unsigned int)*p++) != 0) - result = (result * 16777619) ^ c; - return (size_t)result; - } - }; - #endif - - - /// to_string - /// - /// Converts integral types to an eastl::string with the same content that sprintf produces. The following - /// implementation provides a type safe conversion mechanism which avoids the common bugs associated with sprintf - /// style format strings. - /// - /// http://en.cppreference.com/w/cpp/string/basic_string/to_string - /// - inline string to_string(int value) - { return string(string::CtorSprintf(), "%d", value); } - inline string to_string(long value) - { return string(string::CtorSprintf(), "%ld", value); } - inline string to_string(long long value) - { return string(string::CtorSprintf(), "%lld", value); } - inline string to_string(unsigned value) - { return string(string::CtorSprintf(), "%u", value); } - inline string to_string(unsigned long value) - { return string(string::CtorSprintf(), "%lu", value); } - inline string to_string(unsigned long long value) - { return string(string::CtorSprintf(), "%llu", value); } - inline string to_string(float value) - { return string(string::CtorSprintf(), "%f", value); } - inline string to_string(double value) - { return string(string::CtorSprintf(), "%f", value); } - inline string to_string(long double value) - { return string(string::CtorSprintf(), "%Lf", value); } - - - /// to_wstring - /// - /// Converts integral types to an eastl::wstring with the same content that sprintf produces. The following - /// implementation provides a type safe conversion mechanism which avoids the common bugs associated with sprintf - /// style format strings. - /// - /// http://en.cppreference.com/w/cpp/string/basic_string/to_wstring - /// - inline wstring to_wstring(int value) - { return wstring(wstring::CtorSprintf(), L"%d", value); } - inline wstring to_wstring(long value) - { return wstring(wstring::CtorSprintf(), L"%ld", value); } - inline wstring to_wstring(long long value) - { return wstring(wstring::CtorSprintf(), L"%lld", value); } - inline wstring to_wstring(unsigned value) - { return wstring(wstring::CtorSprintf(), L"%u", value); } - inline wstring to_wstring(unsigned long value) - { return wstring(wstring::CtorSprintf(), L"%lu", value); } - inline wstring to_wstring(unsigned long long value) - { return wstring(wstring::CtorSprintf(), L"%llu", value); } - inline wstring to_wstring(float value) - { return wstring(wstring::CtorSprintf(), L"%f", value); } - inline wstring to_wstring(double value) - { return wstring(wstring::CtorSprintf(), L"%f", value); } - inline wstring to_wstring(long double value) - { return wstring(wstring::CtorSprintf(), L"%Lf", value); } - - - /// user defined literals - /// - /// Converts a character array literal to a basic_string. - /// - /// Example: - /// string s = "abcdef"s; - /// - /// http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s - /// - #if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED - // Disabling the Clang/GCC/MSVC warning about using user - // defined literals without a leading '_' as they are reserved - // for standard libary usage. - EA_DISABLE_VC_WARNING(4455) - EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals) - EA_DISABLE_GCC_WARNING(-Wliteral-suffix) - inline namespace literals - { - inline namespace string_literals - { - inline string operator"" s(const char* str, size_t len) EA_NOEXCEPT { return {str, string::size_type(len)}; } - inline u16string operator"" s(const char16_t* str, size_t len) EA_NOEXCEPT { return {str, u16string::size_type(len)}; } - inline u32string operator"" s(const char32_t* str, size_t len) EA_NOEXCEPT { return {str, u32string::size_type(len)}; } - inline wstring operator"" s(const wchar_t* str, size_t len) EA_NOEXCEPT { return {str, wstring::size_type(len)}; } - - // C++20 char8_t support. - #if EA_CHAR8_UNIQUE - inline u8string operator"" s(const char8_t* str, size_t len) EA_NOEXCEPT { return {str, u8string::size_type(len)}; } - #endif - } - } - EA_RESTORE_GCC_WARNING() // -Wliteral-suffix - EA_RESTORE_CLANG_WARNING() // -Wuser-defined-literals - EA_RESTORE_VC_WARNING() // warning: 4455 - #endif - - - /// erase / erase_if - /// - /// https://en.cppreference.com/w/cpp/string/basic_string/erase2 - template <class CharT, class Allocator, class U> - typename basic_string<CharT, Allocator>::size_type erase(basic_string<CharT, Allocator>& c, const U& value) - { - // Erases all elements that compare equal to value from the container. - auto origEnd = c.end(); - auto newEnd = eastl::remove(c.begin(), origEnd, value); - auto numRemoved = eastl::distance(newEnd, origEnd); - c.erase(newEnd, origEnd); - - // Note: This is technically a lossy conversion when size_type - // is 32bits and ptrdiff_t is 64bits (could happen on 64bit - // systems when EASTL_SIZE_T_32BIT is set). In practice this - // is fine because if EASTL_SIZE_T_32BIT is set then the - // string should not have more characters than fit in a - // uint32_t and so the distance here should fit in a - // size_type. - return static_cast<typename basic_string<CharT, Allocator>::size_type>(numRemoved); - } - - template <class CharT, class Allocator, class Predicate> - typename basic_string<CharT, Allocator>::size_type erase_if(basic_string<CharT, Allocator>& c, Predicate predicate) - { - // Erases all elements that satisfy the predicate pred from the container. - auto origEnd = c.end(); - auto newEnd = eastl::remove_if(c.begin(), origEnd, predicate); - auto numRemoved = eastl::distance(newEnd, origEnd); - c.erase(newEnd, origEnd); - // Note: This is technically a lossy conversion when size_type - // is 32bits and ptrdiff_t is 64bits (could happen on 64bit - // systems when EASTL_SIZE_T_32BIT is set). In practice this - // is fine because if EASTL_SIZE_T_32BIT is set then the - // string should not have more characters than fit in a - // uint32_t and so the distance here should fit in a - // size_type. - return static_cast<typename basic_string<CharT, Allocator>::size_type>(numRemoved); - } -} // namespace eastl - - -EA_RESTORE_VC_WARNING(); - - -#endif // Header include guard |