aboutsummaryrefslogtreecommitdiff
path: root/include/EASTL/string.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/EASTL/string.h')
-rw-r--r--include/EASTL/string.h4296
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