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