1 /*****************************************************************
2 |
3 |   Neptune - String Objects
4 |
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 |     * Redistributions of source code must retain the above copyright
11 |       notice, this list of conditions and the following disclaimer.
12 |     * Redistributions in binary form must reproduce the above copyright
13 |       notice, this list of conditions and the following disclaimer in the
14 |       documentation and/or other materials provided with the distribution.
15 |     * Neither the name of Axiomatic Systems nor the
16 |       names of its contributors may be used to endorse or promote products
17 |       derived from this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30  ****************************************************************/
31 
32 #ifndef _NPT_STRINGS_H_
33 #define _NPT_STRINGS_H_
34 
35 /*----------------------------------------------------------------------
36 |   includes
37 +---------------------------------------------------------------------*/
38 #include "NptConfig.h"
39 #if defined(NPT_CONFIG_HAVE_NEW_H)
40 #include <new>
41 #endif
42 #include "NptTypes.h"
43 #include "NptConstants.h"
44 #include "NptList.h"
45 #include "NptArray.h"
46 #include "NptDebug.h"
47 #include "NptHash.h"
48 
49 /*----------------------------------------------------------------------
50 |   constants
51 +---------------------------------------------------------------------*/
52 const int NPT_STRING_SEARCH_FAILED = -1;
53 
54 /*----------------------------------------------------------------------
55 |   NPT_String
56 +---------------------------------------------------------------------*/
57 class NPT_String
58 {
59 public:
60     // factories
61     static NPT_String FromInteger(NPT_Int64 value);
62     static NPT_String FromIntegerU(NPT_UInt64 value);
63     static NPT_String Format(const char* format, ...);
64 
65     // constructors
66     NPT_String(const NPT_String& str);
67     NPT_String(const char* str);
68     NPT_String(const char* str, NPT_Size length);
69     NPT_String(char c, NPT_Cardinal repeat = 1);
NPT_String()70     NPT_String() : m_Chars(NULL) {}
~NPT_String()71    ~NPT_String() { if (m_Chars) GetBuffer()->Destroy(); }
72 
73     // string info and manipulations
IsEmpty()74     bool       IsEmpty() const { return m_Chars == NULL || GetBuffer()->GetLength() == 0; }
GetLength()75     NPT_Size   GetLength()   const { return m_Chars ? GetBuffer()->GetLength() : 0;    }
GetCapacity()76     NPT_Size   GetCapacity() const { return m_Chars ? GetBuffer()->GetAllocated() : 0; }
77     NPT_Result SetLength(NPT_Size length, bool pad = false);
78     void       Assign(const char* chars, NPT_Size size);
79     void       Append(const char* chars, NPT_Size size);
Append(const char * s)80     void       Append(const char* s) { Append(s, StringLength(s)); }
81     int        Compare(const char* s, bool ignore_case = false) const;
82     static int Compare(const char* s1, const char* s2, bool ignore_case = false);
83     int        CompareN(const char* s, NPT_Size count, bool ignore_case = false) const;
84     static int CompareN(const char* s1, const char* s2, NPT_Size count, bool ignore_case = false);
85 
86     // substrings
87     NPT_String SubString(NPT_Ordinal first, NPT_Size length) const;
SubString(NPT_Ordinal first)88     NPT_String SubString(NPT_Ordinal first) const {
89         return SubString(first, GetLength());
90     }
Left(NPT_Size length)91     NPT_String Left(NPT_Size length) const {
92         return SubString(0, length);
93     }
Right(NPT_Size length)94     NPT_String Right(NPT_Size length) const {
95         return length >= GetLength() ?
96                *this :
97                SubString(GetLength()-length, length);
98     }
99     NPT_List<NPT_String> Split(const char* separator) const;
100     NPT_Array<NPT_String> SplitAny(const char* separator) const;
101     static NPT_String Join(NPT_List<NPT_String>& args, const char* separator);
102 
103     // buffer management
104     void       Reserve(NPT_Size length);
105 
106     // hashing
107     NPT_UInt32 GetHash32() const;
108     NPT_UInt64 GetHash64() const;
109 
110     // conversions
111     NPT_String ToLowercase() const;
112     NPT_String ToUppercase() const;
113     NPT_Result ToInteger(int& value, bool relaxed = true) const;
114     NPT_Result ToInteger(unsigned int& value, bool relaxed = true) const;
115     NPT_Result ToInteger(long& value, bool relaxed = true) const;
116     NPT_Result ToInteger(unsigned long& value, bool relaxed = true) const;
117     NPT_Result ToInteger32(NPT_Int32& value, bool relaxed = true) const;
118     NPT_Result ToInteger32(NPT_UInt32& value, bool relaxed = true) const;
119     NPT_Result ToInteger64(NPT_Int64& value, bool relaxed = true) const;
120     NPT_Result ToInteger64(NPT_UInt64& value, bool relaxed = true) const;
121     NPT_Result ToFloat(float& value, bool relaxed = true) const;
122 
123     // processing
124     void MakeLowercase();
125     void MakeUppercase();
126     const NPT_String& Replace(char a, char b);
127     const NPT_String& Replace(char a, const char* b);
128 
129     // search
130     int  Find(char c, NPT_Ordinal start = 0, bool ignore_case = false) const;
131     int  Find(const char* s, NPT_Ordinal start = 0, bool ignore_case = false) const;
132     int  FindAny(const char* s, NPT_Ordinal start, bool ignore_case = false) const;
133     int  ReverseFind(char c, NPT_Ordinal start = 0, bool ignore_case = false) const;
134     int  ReverseFind(const char* s, NPT_Ordinal start = 0, bool ignore_case = false) const;
135     bool StartsWith(const char* s, bool ignore_case = false) const;
136     bool EndsWith(const char* s, bool ignore_case = false) const;
137 
138     // editing
139     const NPT_String& Insert(const char* s, NPT_Ordinal where = 0);
140     const NPT_String& Erase(NPT_Ordinal start, NPT_Cardinal count = 1);
141     const NPT_String& Replace(const char* before, const char* after);
142     // void Replace(NPT_Ordinal start, NPT_Cardinal count, const char* s);
143     const NPT_String& TrimLeft();
144     const NPT_String& TrimLeft(char c);
145     const NPT_String& TrimLeft(const char* chars);
146     const NPT_String& TrimRight();
147     const NPT_String& TrimRight(char c);
148     const NPT_String& TrimRight(const char* chars);
149     const NPT_String& Trim();
150     const NPT_String& Trim(char c);
151     const NPT_String& Trim(const char* chars);
152 
153     // type casting
154     operator char*() const        { return m_Chars ? m_Chars: &EmptyString; }
155     operator const char* () const { return m_Chars ? m_Chars: &EmptyString; }
GetChars()156     const char* GetChars() const  { return m_Chars ? m_Chars: &EmptyString; }
UseChars()157     char*       UseChars()        { return m_Chars ? m_Chars: &EmptyString; }
158 
159     // operator overloading
160     NPT_String& operator=(const char* str);
161     NPT_String& operator=(const NPT_String& str);
162     NPT_String& operator=(char c);
163     const NPT_String& operator+=(const NPT_String& s) {
164         Append(s.GetChars(), s.GetLength());
165         return *this;
166     }
167     const NPT_String& operator+=(const char* s) {
168         Append(s);
169         return *this;
170     }
171     const NPT_String& operator+=(char c) {
172         Append(&c, 1);
173         return *this;
174     }
175     char operator[](int index) const {
176         NPT_ASSERT((unsigned int)index < GetLength());
177         return GetChars()[index];
178     }
179     char& operator[](int index) {
180         NPT_ASSERT((unsigned int)index < GetLength());
181         return UseChars()[index];
182     }
183 
184     // friend operators
185     friend NPT_String operator+(const NPT_String& s1, const NPT_String& s2) {
186         return s1+s2.GetChars();
187     }
188     friend NPT_String operator+(const NPT_String& s1, const char* s2);
189     friend NPT_String operator+(const char* s1, const NPT_String& s2);
190     friend NPT_String operator+(const NPT_String& s, char c);
191     friend NPT_String operator+(char c, const NPT_String& s);
192 
193 protected:
194     // inner classes
195     class Buffer {
196     public:
197         // class methods
Allocate(NPT_Size allocated,NPT_Size length)198         static Buffer* Allocate(NPT_Size allocated, NPT_Size length) {
199             void* mem = ::operator new(sizeof(Buffer)+allocated+1);
200             return new(mem) Buffer(allocated, length);
201         }
202         static char* Create(NPT_Size allocated, NPT_Size length=0) {
203             Buffer* shared = Allocate(allocated, length);
204             return shared->GetChars();
205         }
Create(const char * copy)206         static char* Create(const char* copy) {
207             NPT_Size length = StringLength(copy);
208             Buffer* shared = Allocate(length, length);
209             CopyString(shared->GetChars(), copy);
210             return shared->GetChars();
211         }
Create(const char * copy,NPT_Size length)212         static char* Create(const char* copy, NPT_Size length) {
213             Buffer* shared = Allocate(length, length);
214             CopyBuffer(shared->GetChars(), copy, length);
215             shared->GetChars()[length] = '\0';
216             return shared->GetChars();
217         }
Create(char c,NPT_Cardinal repeat)218         static char* Create(char c, NPT_Cardinal repeat) {
219             Buffer* shared = Allocate(repeat, repeat);
220             char* s = shared->GetChars();
221             while (repeat--) {
222                 *s++ = c;
223             }
224             *s = '\0';
225             return shared->GetChars();
226         }
227 
228         // methods
GetChars()229         char* GetChars() {
230             // return a pointer to the first char
231             return reinterpret_cast<char*>(this+1);
232         }
GetLength()233         NPT_Size GetLength() const      { return m_Length; }
SetLength(NPT_Size length)234         void SetLength(NPT_Size length) { m_Length = length; }
GetAllocated()235         NPT_Size GetAllocated() const   { return m_Allocated; }
Destroy()236         void Destroy() { ::operator delete((void*)this); }
237 
238     private:
239         // methods
240         Buffer(NPT_Size allocated, NPT_Size length = 0) :
m_Length(length)241             m_Length(length),
242             m_Allocated(allocated) {}
243 
244         // members
245         NPT_Cardinal m_Length;
246         NPT_Cardinal m_Allocated;
247         // the actual string data follows
248 
249     };
250 
251     // members
252     char* m_Chars;
253 
254 private:
255     // friends
256     friend class Buffer;
257 
258     // static members
259     static char EmptyString;
260 
261     // methods
GetBuffer()262     Buffer* GetBuffer() const {
263         return reinterpret_cast<Buffer*>(m_Chars)-1;
264     }
Reset()265     void Reset() {
266         if (m_Chars != NULL) {
267             delete GetBuffer();
268             m_Chars = NULL;
269         }
270     }
271     char* PrepareToWrite(NPT_Size length);
272     void PrepareToAppend(NPT_Size length, NPT_Size allocate);
273 
274     // static methods
CopyString(char * dst,const char * src)275     static void CopyString(char* dst, const char* src) {
276         while ((*dst++ = *src++)){}
277     }
278 
CopyBuffer(char * dst,const char * src,NPT_Size size)279     static void CopyBuffer(char* dst, const char* src, NPT_Size size) {
280         while (size--) *dst++ = *src++;
281     }
282 
StringLength(const char * str)283     static NPT_Size StringLength(const char* str) {
284         NPT_Size length = 0;
285         while (*str++) length++;
286         return length;
287     }
288 };
289 
290 /*----------------------------------------------------------------------
291 |   external operators
292 +---------------------------------------------------------------------*/
293 inline bool operator==(const NPT_String& s1, const NPT_String& s2) {
294     return s1.Compare(s2) == 0;
295 }
296 inline bool operator==(const NPT_String& s1, const char* s2) {
297     return s1.Compare(s2) == 0;
298 }
299 inline bool operator==(const char* s1, const NPT_String& s2) {
300     return s2.Compare(s1) == 0;
301 }
302 inline bool operator!=(const NPT_String& s1, const NPT_String& s2) {
303     return s1.Compare(s2) != 0;
304 }
305 inline bool operator!=(const NPT_String& s1, const char* s2) {
306     return s1.Compare(s2) != 0;
307 }
308 inline bool operator!=(const char* s1, const NPT_String& s2) {
309     return s2.Compare(s1) != 0;
310 }
311 inline bool operator<(const NPT_String& s1, const NPT_String& s2) {
312     return s1.Compare(s2) < 0;
313 }
314 inline bool operator<(const NPT_String& s1, const char* s2) {
315     return s1.Compare(s2) < 0;
316 }
317 inline bool operator<(const char* s1, const NPT_String& s2) {
318     return s2.Compare(s1) > 0;
319 }
320 inline bool operator>(const NPT_String& s1, const NPT_String& s2) {
321     return s1.Compare(s2) > 0;
322 }
323 inline bool operator>(const NPT_String& s1, const char* s2) {
324     return s1.Compare(s2) > 0;
325 }
326 inline bool operator>(const char* s1, const NPT_String& s2) {
327     return s2.Compare(s1) < 0;
328 }
329 inline bool operator<=(const NPT_String& s1, const NPT_String& s2) {
330     return s1.Compare(s2) <= 0;
331 }
332 inline bool operator<=(const NPT_String& s1, const char* s2) {
333     return s1.Compare(s2) <= 0;
334 }
335 inline bool operator<=(const char* s1, const NPT_String& s2) {
336     return s2.Compare(s1) >= 0;
337 }
338 inline bool operator>=(const NPT_String& s1, const NPT_String& s2) {
339     return s1.Compare(s2) >= 0;
340 }
341 inline bool operator>=(const NPT_String& s1, const char* s2) {
342     return s1.Compare(s2) >= 0;
343 }
344 inline bool operator>=(const char* s1, const NPT_String& s2) {
345     return s2.Compare(s1) <= 0;
346 }
347 
348 /*----------------------------------------------------------------------
349 |   hashing
350 +---------------------------------------------------------------------*/
351 template <>
352 struct NPT_Hash<NPT_String>
353 {
354     NPT_UInt32 operator()(const NPT_String& s) const { return s.GetHash32(); }
355 };
356 
357 
358 #endif // _NPT_STRINGS_H_
359