1 /////////////////////////////////////////////////////////////////////////////// 2 // Copyright (c) Electronic Arts Inc. All rights reserved. 3 /////////////////////////////////////////////////////////////////////////////// 4 5 6 #ifndef EASTL_FIXED_SUBSTRING_H 7 #define EASTL_FIXED_SUBSTRING_H 8 9 10 #include <EASTL/string.h> 11 12 #if defined(EA_PRAGMA_ONCE_SUPPORTED) 13 #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. 14 #endif 15 16 17 18 namespace eastl 19 { 20 21 /// fixed_substring 22 /// 23 /// Implements a string which is a reference to a segment of characters. 24 /// This class is efficient because it allocates no memory and copies no 25 /// memory during construction and assignment, but rather refers directly 26 /// to the segment of chracters. A common use of this is to have a 27 /// fixed_substring efficiently refer to a substring within another string. 28 /// 29 /// You cannot directly resize a fixed_substring (e.g. via resize, insert, 30 /// append, erase), but you can assign a different substring to it. 31 /// You can modify the characters within a substring in place. 32 /// As of this writing, in the name of being lean and simple it is the 33 /// user's responsibility to not call unsupported resizing functions 34 /// such as those listed above. A detailed listing of the functions which 35 /// are not supported is given below in the class declaration. 36 /// 37 /// The c_str function doesn't act as one might hope, as it simply 38 /// returns the pointer to the beginning of the string segment and the 39 /// 0-terminator may be beyond the end of the segment. If you want to 40 /// always be able to use c_str as expected, use the fixed string solution 41 /// we describe below. 42 /// 43 /// Another use of fixed_substring is to provide C++ string-like functionality 44 /// with a C character array. This allows you to work on a C character array 45 /// as if it were a C++ string as opposed using the C string API. Thus you 46 /// can do this: 47 /// 48 /// void DoSomethingForUser(char* timeStr, size_t timeStrCapacity) 49 /// { 50 /// fixed_substring tmp(timeStr, timeStrCapacity); 51 /// tmp = "hello "; 52 /// tmp += "world"; 53 /// } 54 /// 55 /// Note that this class constructs and assigns from const string pointers 56 /// and const string objects, yet this class does not declare its member 57 /// data as const. This is a concession in order to allow this implementation 58 /// to be simple and lean. It is the user's responsibility to make sure 59 /// that strings that should not or can not be modified are either not 60 /// used by fixed_substring or are not modified by fixed_substring. 61 /// 62 /// A more flexible alternative to fixed_substring is fixed_string. 63 /// fixed_string has none of the functional limitations that fixed_substring 64 /// has and like fixed_substring it doesn't allocate memory. However, 65 /// fixed_string makes a *copy* of the source string and uses local 66 /// memory to store that copy. Also, fixed_string objects on the stack 67 /// are going to have a limit as to their maximum size. 68 /// 69 /// Notes: 70 /// As of this writing, the string class necessarily reallocates when 71 /// an insert of self is done into self. As a result, the fixed_substring 72 /// class doesn't support inserting self into self. 73 /// 74 /// Example usage: 75 /// basic_string<char> str("hello world"); 76 /// fixed_substring<char> sub(str, 2, 5); // sub == "llo w" 77 /// 78 template <typename T> 79 class fixed_substring : public basic_string<T> 80 { 81 public: 82 typedef basic_string<T> base_type; 83 typedef fixed_substring<T> this_type; 84 typedef typename base_type::size_type size_type; 85 typedef typename base_type::value_type value_type; 86 typedef typename base_type::iterator iterator; 87 typedef typename base_type::const_iterator const_iterator; 88 89 using base_type::npos; 90 using base_type::mPair; 91 using base_type::AllocateSelf; 92 using base_type::internalLayout; 93 using base_type::get_allocator; 94 95 private: 96 SetInternalHeapLayout(value_type * pBeginPtr,size_type nSize,size_type nCap)97 void SetInternalHeapLayout(value_type* pBeginPtr, size_type nSize, size_type nCap) 98 { 99 internalLayout().SetHeapBeginPtr(pBeginPtr); 100 internalLayout().SetHeapSize(nSize); 101 internalLayout().SetHeapCapacity(nCap); 102 } 103 104 105 public: fixed_substring()106 fixed_substring() 107 : base_type() 108 { 109 } 110 fixed_substring(const base_type & x)111 fixed_substring(const base_type& x) 112 : base_type() 113 { 114 #if EASTL_NAME_ENABLED 115 get_allocator().set_name(x.get_allocator().get_name()); 116 #endif 117 118 assign(x); 119 } 120 121 // We gain no benefit from having an rvalue move constructor or assignment operator, 122 // as this class is a const class. 123 124 fixed_substring(const base_type& x, size_type position, size_type n = base_type::npos) base_type()125 : base_type() 126 { 127 #if EASTL_NAME_ENABLED 128 get_allocator().set_name(x.get_allocator().get_name()); 129 #endif 130 131 assign(x, position, n); 132 } 133 fixed_substring(const value_type * p,size_type n)134 fixed_substring(const value_type* p, size_type n) 135 : base_type() 136 { 137 assign(p, n); 138 } 139 fixed_substring(const value_type * p)140 fixed_substring(const value_type* p) 141 : base_type() 142 { 143 assign(p); 144 } 145 fixed_substring(const value_type * pBegin,const value_type * pEnd)146 fixed_substring(const value_type* pBegin, const value_type* pEnd) 147 : base_type() 148 { 149 assign(pBegin, pEnd); 150 } 151 ~fixed_substring()152 ~fixed_substring() 153 { 154 // We need to reset, as otherwise the parent destructor will 155 // attempt to free our memory. 156 AllocateSelf(); 157 } 158 159 this_type& operator=(const base_type& x) 160 { 161 assign(x); 162 return *this; 163 } 164 165 this_type& operator=(const value_type* p) 166 { 167 assign(p); 168 return *this; 169 } 170 assign(const base_type & x)171 this_type& assign(const base_type& x) 172 { 173 // By design, we need to cast away const-ness here. 174 SetInternalHeapLayout(const_cast<value_type*>(x.data()), x.size(), x.size()); 175 return *this; 176 } 177 assign(const base_type & x,size_type position,size_type n)178 this_type& assign(const base_type& x, size_type position, size_type n) 179 { 180 // By design, we need to cast away const-ness here. 181 SetInternalHeapLayout(const_cast<value_type*>(x.data()) + position, n, n); 182 return *this; 183 } 184 assign(const value_type * p,size_type n)185 this_type& assign(const value_type* p, size_type n) 186 { 187 // By design, we need to cast away const-ness here. 188 SetInternalHeapLayout(const_cast<value_type*>(p), n, n); 189 return *this; 190 } 191 assign(const value_type * p)192 this_type& assign(const value_type* p) 193 { 194 // By design, we need to cast away const-ness here. 195 SetInternalHeapLayout(const_cast<value_type*>(p), (size_type)CharStrlen(p), (size_type)CharStrlen(p)); 196 return *this; 197 } 198 assign(const value_type * pBegin,const value_type * pEnd)199 this_type& assign(const value_type* pBegin, const value_type* pEnd) 200 { 201 // By design, we need to cast away const-ness here. 202 SetInternalHeapLayout(const_cast<value_type*>(pBegin), (size_type)(pEnd - pBegin), (size_type)(pEnd - pBegin)); 203 return *this; 204 } 205 206 207 // Partially supported functionality 208 // 209 // When using fixed_substring on a character sequence that is within another 210 // string, the following functions may do one of two things: 211 // 1 Attempt to reallocate 212 // 2 Write a 0 char at the end of the fixed_substring 213 // 214 // Item #1 will result in a crash, due to the attempt by the underlying 215 // string class to free the substring memory. Item #2 will result in a 0 216 // char being written to the character array. Item #2 may or may not be 217 // a problem, depending on how you use fixed_substring. Thus the following 218 // functions cannot be used safely. 219 220 #if 0 // !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) We may want to enable these deletions after some investigation of possible user impact. 221 this_type& operator=(value_type c) = delete; 222 void resize(size_type n, value_type c) = delete; 223 void resize(size_type n) = delete; 224 void reserve(size_type = 0) = delete; 225 void set_capacity(size_type n) = delete; 226 void clear() = delete; 227 this_type& operator+=(const base_type& x) = delete; 228 this_type& operator+=(const value_type* p) = delete; 229 this_type& operator+=(value_type c) = delete; 230 this_type& append(const base_type& x) = delete; 231 this_type& append(const base_type& x, size_type position, size_type n) = delete; 232 this_type& append(const value_type* p, size_type n) = delete; 233 this_type& append(const value_type* p) = delete; 234 this_type& append(size_type n) = delete; 235 this_type& append(size_type n, value_type c) = delete; 236 this_type& append(const value_type* pBegin, const value_type* pEnd) = delete; 237 this_type& append_sprintf_va_list(const value_type* pFormat, va_list arguments) = delete; 238 this_type& append_sprintf(const value_type* pFormat, ...) = delete; 239 void push_back(value_type c) = delete; 240 void pop_back() = delete; 241 this_type& assign(size_type n, value_type c) = delete; 242 this_type& insert(size_type position, const base_type& x) = delete; 243 this_type& insert(size_type position, const base_type& x, size_type beg, size_type n) = delete; 244 this_type& insert(size_type position, const value_type* p, size_type n) = delete; 245 this_type& insert(size_type position, const value_type* p) = delete; 246 this_type& insert(size_type position, size_type n, value_type c) = delete; 247 iterator insert(const_iterator p, value_type c) = delete; 248 void insert(const_iterator p, size_type n, value_type c) = delete; 249 void insert(const_iterator p, const value_type* pBegin, const value_type* pEnd) = delete; 250 this_type& erase(size_type position = 0, size_type n = npos) = delete; 251 iterator erase(const_iterator p) = delete; 252 iterator erase(const_iterator pBegin, const_iterator pEnd) = delete; 253 void swap(base_type& x) = delete; 254 this_type& sprintf_va_list(const value_type* pFormat, va_list arguments) = delete; 255 this_type& sprintf(const value_type* pFormat, ...) = delete; 256 #endif 257 258 }; // fixed_substring 259 260 261 } // namespace eastl 262 263 264 265 #endif // Header include guard 266