NXWidgets  1.19
cnxstring.cxx
Go to the documentation of this file.
1 /****************************************************************************
2  * NxWidgets/libnxwidgets/src/cnxstring.cxx
3  *
4  * Copyright (C) 2012 Gregory Nutt. All rights reserved.
5  * Author: Gregory Nutt <gnutt@nuttx.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  * 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
18  * me be used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  ****************************************************************************
35  *
36  * Portions of this package derive from Woopsi (http://woopsi.org/) and
37  * portions are original efforts. It is difficult to determine at this
38  * point what parts are original efforts and which parts derive from Woopsi.
39  * However, in any event, the work of Antony Dzeryn will be acknowledged
40  * in most NxWidget files. Thanks Antony!
41  *
42  * Copyright (c) 2007-2011, Antony Dzeryn
43  * All rights reserved.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions are met:
47  *
48  * * Redistributions of source code must retain the above copyright
49  * notice, this list of conditions and the following disclaimer.
50  * * Redistributions in binary form must reproduce the above copyright
51  * notice, this list of conditions and the following disclaimer in the
52  * documentation and/or other materials provided with the distribution.
53  * * Neither the names "Woopsi", "Simian Zombie" nor the
54  * names of its contributors may be used to endorse or promote products
55  * derived from this software without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY Antony Dzeryn ``AS IS'' AND ANY
58  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
59  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
60  * DISCLAIMED. IN NO EVENT SHALL Antony Dzeryn BE LIABLE FOR ANY
61  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
62  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
63  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
64  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
66  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67  *
68  ****************************************************************************/
69 
70 /****************************************************************************
71  * Included Files
72  ****************************************************************************/
73 
74 #include <nuttx/config.h>
75 
76 #include <sys/types.h>
77 #include <stdint.h>
78 #include <stdbool.h>
79 #include <string.h>
80 
81 #include "cnxstring.hxx"
82 #include "cstringiterator.hxx"
83 
84 /****************************************************************************
85  * Pre-Processor Definitions
86  ****************************************************************************/
87 
88 /****************************************************************************
89  * CNxString Method Implementations
90  ****************************************************************************/
91 
92 using namespace NXWidgets;
93 
94 /**
95  * Constructor to create an empty string object.
96  */
97 
99 {
100  m_text = (FAR nxwidget_char_t *)NULL;
101  m_stringLength = 0;
102  m_allocatedSize = 0;
103  m_growAmount = 16;
104 }
105 
106 /**
107  * Constructor to create a string from a C character array.
108  *
109  * @param text Pointer to a char array to use as the basis of the
110  * string.
111  */
112 
113 CNxString::CNxString(FAR const char *text)
114 {
115  m_text = (FAR nxwidget_char_t *)NULL;
116  m_stringLength = 0;
117  m_allocatedSize = 0;
118  m_growAmount = 16;
119 
120  setText(text);
121 }
122 
123 /**
124  * Constructor to create a string from a single character.
125  * @param letter Single character to use as the basis of the string.
126  */
127 
129 {
130  m_text = (FAR nxwidget_char_t *)NULL;
131  m_stringLength = 0;
132  m_allocatedSize = 0;
133  m_growAmount = 16;
134 
135  setText(text);
136 }
137 
139 {
140  m_text = (FAR nxwidget_char_t *)NULL;
141  m_stringLength = 0;
142  m_allocatedSize = 0;
143  m_growAmount = 16;
144 
145  setText(string);
146 }
147 
148 /**
149  * Creates and returns a new CCStringIterator object that will iterate
150  * over this string. The object must be manually deleted once it is
151  * no longer needed.
152  *
153  * @return A new CCStringIterator object.
154  */
155 
157 {
158  return new CStringIterator(this);
159 }
160 
161 /**
162  * Copy the internal array to the supplied buffer. The buffer must be
163  * large enough to contain the full text in the string. The
164  * getAllocSize() method can be used to obtain the length of the string.
165  * Unlike the CNxString class, the char array is null-terminated.
166  * The buffer must be (getAllocSize() + 2) bytes long, in order to
167  * accommodate the terminator.
168  *
169  * @param buffer Buffer to copy the internal char array to.
170  */
171 
173 {
174  unsigned int dataLength = sizeof(nxwidget_char_t) * m_stringLength;
175  memcpy(buffer, m_text, dataLength);
176  buffer[dataLength] = '\0';
177 }
178 
179 /**
180  * Set the text in the string.
181  *
182  * @param text CNxString containing the new data for this string.
183  */
184 
185 void CNxString::setText(const CNxString &text)
186 {
187  // Ensure we've got enough memory available
188 
189  allocateMemory(text.getLength(), false);
190 
191  // Copy the text into the internal array
192 
193  memcpy(m_text, text.getCharArray(), sizeof(nxwidget_char_t) * text.getLength());
194 
195  // Save size (in characters) of the string
196 
197  m_stringLength = text.getLength();
198 }
199 
200 /**
201  * Set the 8-bit C-string text in the string.
202  *
203  * @param text Char array to use as the new data for this string.
204  */
205 
206 void CNxString::setText(FAR const char *text)
207 {
208  int length = strlen(text);
209 
210  // Ensure we've got enough memory available
211 
212  allocateMemory(length, false);
213 
214  // Copy characters into m_text, converting from 8- to 16-bit characters
215  // (if necessary) and cache the length
216 
217  for (int i = 0; i < length; i++)
218  {
219  m_text[i] = (nxwidget_char_t)text[i];
220  }
221 
222  m_stringLength = length;
223 }
224 
225 /**
226  * Set the text in the string.
227  *
228  * @param text Char array to use as the new data for this string.
229  */
230 
231 void CNxString::setText(FAR const nxwidget_char_t *text, int nchars)
232 {
233  // Ensure we've got enough memory available
234 
235  allocateMemory(nchars, false);
236 
237  // Copy characters into m_text and cache the length
238 
239  m_stringLength = nchars;
240  memcpy(m_text, text, sizeof(nxwidget_char_t) * nchars);
241 }
242 
243 /**
244  * Set the text in the string.
245  *
246  * @param text Character to to use as the new data for this string.
247  */
248 
250 {
251  // Ensure we've got enough memory available
252 
253  allocateMemory(1, false);
254 
255  // Copy the valid character into m_text and cache the length
256 
257  *m_text = letter;
258  m_stringLength = 1;
259 }
260 
261 /**
262  * Append text to the end of the string.
263  *
264  * @param text String to append.
265  */
266 
267 void CNxString::append(const CNxString &text)
268 {
269  // Ensure we've got enough memory available
270 
271  allocateMemory(m_stringLength + text.getLength(), true);
272 
273  // Append the new string to the end of the array
274 
275  FAR nxwidget_char_t *dest = &m_text[m_stringLength];
276  FAR const nxwidget_char_t *src = text.getCharArray();
277 
278  for (unsigned int i = 0; i < text.getLength(); i++)
279  {
280  *dest++ = *src++;
281  }
282 
283  // Update the size in characters and the size in bytes
284 
285  m_stringLength += text.getLength();
286 }
287 
288 /**
289  * Insert text at the specified character index.
290  *
291  * @param text The text to insert.
292  * @param index The index at which to insert the text.
293  */
294 
295 void CNxString::insert(const CNxString &text, int index)
296 {
297  // Early exit if the string is empty
298 
299  if (!hasData())
300  {
301  CNxString::setText(text);
302  return;
303  }
304 
305  // Early exit if we're just appending
306 
307  if (index >= m_stringLength)
308  {
309  CNxString::append(text);
310  return;
311  }
312 
313  // Get the total size of the string that we need
314 
315  int newLength = m_stringLength + text.getLength();
316  int newSize = newLength * sizeof(nxwidget_char_t);
317 
318  // Reallocate memory if the existing memory isn't large enough
319 
320  if (m_allocatedSize < newSize)
321  {
322  int allocLength = newLength + m_growAmount;
323 
324  // Allocate new string large enough to contain additional data
325 
326  FAR nxwidget_char_t *newText = new nxwidget_char_t[allocLength];
327 
328  // Copy the start of the existing text to the newly allocated string
329 
330  FAR nxwidget_char_t *dest = newText;
331  FAR const nxwidget_char_t *src = m_text;
332 
333  for (int i = 0; i < index; i++)
334  {
335  *dest++ = *src++;
336  }
337 
338  // Insert the additional text into the new string
339 
340  src = text.getCharArray();
341 
342  for (unsigned int i = 0; i < text.getLength(); i++)
343  {
344  *dest++ = *src++;
345  }
346 
347  // Copy the end of the existing text the the newly allocated string
348 
349  src = &m_text[index];
350 
351  for (int i = index; i < m_stringLength; i++)
352  {
353  *dest++ = *src++;
354  }
355 
356  m_allocatedSize = allocLength * sizeof(nxwidget_char_t);
357 
358  // Delete existing string
359 
360  delete[] m_text;
361 
362  // Swap pointers
363 
364  m_stringLength = newLength;
365  m_text = newText;
366  }
367  else
368  {
369  // Existing size is large enough, so make space in string for insert
370 
371  FAR nxwidget_char_t *dest = &m_text[newLength - 1];
372  FAR const nxwidget_char_t *src = &m_text[m_stringLength - 1];
373  for (int i = 0; i < m_stringLength - index; i++)
374  {
375  *dest-- = *src--;
376  }
377 
378  // Insert the additional text into the new string
379 
380  dest = &m_text[index];
381  src = text.getCharArray();
382 
383  for (unsigned int i = 0; i < text.getLength(); i++)
384  {
385  *dest++ = *src++;
386  }
387 
388  m_stringLength = newLength;
389  }
390 }
391 
392 /**
393  * Remove all characters from the string from the start index onwards.
394  *
395  * @param startIndex Index to remove from.
396  */
397 
398 void CNxString::remove(const int startIndex)
399 {
400  // Reject if requested operation makes no sense
401 
402  if (!hasData() || startIndex >= m_stringLength)
403  {
404  return;
405  }
406 
407  // Removing characters from the end of the string is trivial - simply
408  // decrease the length
409 
410  m_stringLength = startIndex;
411 }
412 
413 /**
414  * Remove specified number of characters from the string from the
415  * start index onwards.
416  *
417  * @param startIndex Index to remove from.
418  * @param count Number of characters to remove.
419  */
420 
421 void CNxString::remove(const int startIndex, const int count)
422 {
423  // Reject if requested operation makes no sense
424 
425  if (!hasData() || startIndex >= m_stringLength)
426  {
427  return;
428  }
429 
430  // Don't remove in this way if the count includes the end of the string
431 
432  int endIndex = startIndex + count;
433  if (endIndex > m_stringLength)
434  {
435  remove(startIndex);
436  return;
437  }
438 
439  // Copy characters from a point after the area to be deleted into the space created
440  // by the deletion
441 
442  FAR nxwidget_char_t *dest = &m_text[startIndex];
443  FAR const nxwidget_char_t *src = &m_text[endIndex];
444 
445  for (int i = m_stringLength - endIndex; i > 0; i--)
446  {
447  *dest++ = *src++;
448  }
449 
450  // Decrease length
451 
452  m_stringLength -= count;
453 
454 }
455 
456 /**
457  * Get the character at the specified index. This function is useful
458  * for finding the occasional character at an index, but for iterating
459  * over strings it is exceptionally slow. The newStringIterator()
460  * method should be used to retrieve an iterator object that can iterate
461  * over the string efficiently.
462  *
463  * @param index The index of the character to retrieve.
464  * @return The character at the specified index.
465  */
466 
467 const nxwidget_char_t CNxString::getCharAt(int index) const
468 {
469  return *getCharPointer(index);
470 }
471 
472 /**
473  * Returns the first index of the specified letter within the string.
474  * Will return -1 if the letter is not found.
475  *
476  * @param letter Letter to find.
477  * @return The index of the letter.
478  */
479 
480 const int CNxString::indexOf(nxwidget_char_t letter) const
481 {
482  return indexOf(letter, 0, getLength());
483 }
484 
485 /**
486  * Returns the first index of the specified letter within the string.
487  * Will return -1 if the letter is not found. Scans through the string
488  * from "startIndex" until it has examined all subsequent letters.
489  *
490  * @param letter Letter to find.
491  * @param startIndex The index to start searching from.
492  * @return The index of the letter.
493  */
494 
495 const int CNxString::indexOf(nxwidget_char_t letter, int startIndex) const
496 {
497  return indexOf(letter, startIndex, getLength() - startIndex);
498 }
499 
500 /**
501  * Returns the first index of the specified letter within the string.
502  * Will return -1 if the letter is not found. Scans through the string
503  * from "startIndex" until it has examined all letters within the
504  * range "count".
505  *
506  * @param letter Letter to find.
507  * @param startIndex The index to start searching from.
508  * @param count The number of characters to examine.
509  * @return The index of the letter.
510  */
511 
512 const int CNxString::indexOf(nxwidget_char_t letter, int startIndex, int count) const
513 {
514  // Exit if no data available
515 
516  if (!hasData())
517  {
518  return -1;
519  }
520 
521  int index = -1;
522  int charsExamined = 0;
523 
524  CStringIterator *iterator = new CStringIterator(this);
525  if (!iterator->moveTo(startIndex))
526  {
527  delete iterator;
528  return -1;
529  }
530 
531  do
532  {
533  if (iterator->getChar() == letter)
534  {
535  index = iterator->getIndex();
536  break;
537  }
538 
539  charsExamined++;
540  }
541  while (iterator->moveToNext() && (charsExamined < count));
542 
543  delete iterator;
544  return index;
545 }
546 
547 /**
548  * Returns the last index of the specified letter within the string.
549  * Will return -1 if the letter is not found.
550  *
551  * @param letter Letter to find.
552  * @return The index of the letter.
553  */
554 
556 {
557  return lastIndexOf(letter, getLength() - 1, getLength());
558 }
559 
560 /**
561  * Returns the last index of the specified letter within the string.
562  * Will return -1 if the letter is not found. Scans through the string
563  * backwards from "startIndex" until it has examined all preceding
564  * letters within the string.
565  *
566  * @param letter Letter to find.
567  * @param startIndex The index to start searching from.
568  * @return The index of the letter.
569  */
570 
571 const int CNxString::lastIndexOf(nxwidget_char_t letter, int startIndex) const
572 {
573  return lastIndexOf(letter, startIndex, getLength() - (getLength() - startIndex));
574 }
575 
576 /**
577  * Returns the last index of the specified letter within the string.
578  * Will return -1 if the letter is not found. Scans through the string
579  * backwards from "startIndex" until it has examined all letters within
580  * the range "count".
581  * @param letter Letter to find.
582  * @param startIndex The index to start searching from.
583  * @param count The number of characters to examine.
584  * @return The index of the letter.
585  */
586 
587 const int CNxString::lastIndexOf(nxwidget_char_t letter, int startIndex, int count) const
588 {
589  // Exit if no data available
590 
591  if (!hasData())
592  {
593  return -1;
594  }
595 
596  int index = -1;
597  int charsExamined = 0;
598 
599  CStringIterator *iterator = new CStringIterator(this);
600  if (!iterator->moveTo(startIndex))
601  {
602  delete iterator;
603  return -1;
604  }
605 
606  do
607  {
608  if (iterator->getChar() == letter)
609  {
610  index = iterator->getIndex();
611  break;
612  }
613 
614  charsExamined++;
615  }
616  while (iterator->moveToPrevious() && (charsExamined <= count));
617 
618  delete iterator;
619  return index;
620 }
621 
622 /**
623  * Get a substring from this string. It is the responsibility of the
624  * caller to delete the substring when it is no longer required.
625  *
626  * @param startIndex The starting point of the substring.
627  * @return A pointer to a new CNxString object containing the
628  * substring.
629  */
630 
631 CNxString* CNxString::subString(int startIndex) const
632 {
633  return subString(startIndex, getLength() - startIndex);
634 }
635 
636 /**
637  * Get a substring from this string. It is the responsibility of the
638  * caller to delete the substring when it is no longer required.
639  *
640  * @param startIndex The starting point of the substring.
641  * @param length The length of the substring.
642  * @return A pointer to a new CNxString object containing the
643  * substring.
644 */
645 
646 CNxString *CNxString::subString(int startIndex, int length) const
647 {
648  CNxString *newString = new CNxString();
649  CStringIterator *iterator = new CStringIterator(this);
650 
651  if (!iterator->moveTo(startIndex))
652  {
653  delete iterator;
654  return (CNxString *)0;
655  }
656 
657  // Build up the string character by character. We could do a memcpy
658  // here and improve performance.
659 
660  int count = 0;
661  while (count < length)
662  {
663  newString->append(iterator->getChar());
664  iterator->moveToNext();
665  count++;
666  }
667 
668  delete iterator;
669  return newString;
670 }
671 
672 /**
673  * Overloaded assignment operator. Copies the data within the argument
674  * string to this string.
675  *
676  * @param string The string to copy.
677  * @return This string.
678  */
679 
681 {
682  if (&string != this)
683  {
684  setText(string);
685  }
686 
687  return *this;
688 }
689 
690 /**
691  * Overloaded assignment operator. Copies the data within the argument
692  * char array to this string.
693  *
694  * @param string The string to copy.
695  * @return This string.
696  */
697 
698 CNxString& CNxString::operator=(FAR const char *string)
699 {
700  setText(string);
701  return *this;
702 }
703 
704 /**
705  * Overloaded assignment operator. Copies the data from the argument
706  * char to this string.
707  *
708  * @param letter The char to copy.
709  * @return This string.
710  */
711 
713 {
714  setText(letter);
715  return *this;
716 }
717 
718 /**
719  * Compares this string to the argument.
720  *
721  * @param string String to compare to.
722  * @return Zero if both strings are equal. A value greater than zero
723  * indicates that this string is greater than the argument string. A
724  * value less than zero indicates the opposite. Note that the return
725  * value indicates the *byte* that does not match, not the *character*.
726  */
727 
728 int CNxString::compareTo(const CNxString &string) const
729 {
730  return memcmp((FAR const char*)m_text,
731  (FAR const char*)string.getCharArray(),
732  getLength());
733 }
734 
735 /**
736  * Allocate memory for the string.
737  *
738  * @param chars Number nxwidget_char_t size characters to allocate.
739  * @param preserve If true, the data in the existing memory will be
740  * preserved if new memory must be allocated
741  */
742 
743 void CNxString::allocateMemory(int nChars, bool preserve)
744 {
745  // This is the size of the allocation that we need
746 
747  int nBytesNeeded = nChars * sizeof(nxwidget_char_t);
748 
749  // Do we already have enough memory allocated to contain this new size?
750  // If so, we can avoid deallocating and allocating new memory by re-using the old
751 
752  if (nBytesNeeded > m_allocatedSize)
753  {
754  // Not enough space in existing memory; allocate new memory
755 
756  int allocChars = nChars + m_growAmount;
757  nxwidget_char_t *newText = new nxwidget_char_t[allocChars];
758 
759  // Free old memory if necessary
760 
761  if (m_text != NULL)
762  {
763  // Preserve existing data if required
764 
765  if (preserve)
766  {
767  memcpy(newText, m_text, sizeof(nxwidget_char_t) * m_stringLength);
768  }
769 
770  delete[] m_text;
771  }
772 
773  // Set pointer to new memory
774 
775  m_text = newText;
776 
777  // Remember how much memory we've allocated.
778 
779  m_allocatedSize = allocChars * sizeof(nxwidget_char_t);
780  }
781 }
782 
783 /**
784  * Return a pointer to the specified characters.
785  *
786  * @param index Index of the character to retrieve.
787  */
788 
789 FAR nxwidget_char_t *CNxString::getCharPointer(const int index) const
790 {
791  // Early exit if the string is empty
792 
793  if (!hasData())
794  {
795  return (FAR nxwidget_char_t*)NULL;
796  }
797 
798  // Early exit if the index is greater than the length of the string
799 
800  if (index >= m_stringLength)
801  {
802  return (FAR nxwidget_char_t*)NULL;
803  }
804 
805  return &m_text[index];
806 }
int compareTo(const CNxString &string) const
Definition: cnxstring.cxx:728
const int lastIndexOf(nxwidget_char_t letter) const
Definition: cnxstring.cxx:555
void append(const CNxString &text)
Definition: cnxstring.cxx:267
FAR nxwidget_char_t * getCharPointer(const int index) const
Definition: cnxstring.cxx:789
friend class CStringIterator
Definition: cnxstring.hxx:124
CNxString & operator=(const CNxString &string)
Definition: cnxstring.cxx:680
void remove(const int startIndex)
Definition: cnxstring.cxx:398
const int indexOf(nxwidget_char_t letter) const
Definition: cnxstring.cxx:480
uint16_t nxwidget_char_t
Definition: nxconfig.hxx:454
nxwidget_char_t getChar(void) const
void setText(const CNxString &text)
Definition: cnxstring.cxx:185
bool hasData(void) const
Definition: cnxstring.hxx:152
void allocateMemory(int chars, bool preserve)
Definition: cnxstring.cxx:743
FAR const nxwidget_char_t * getCharArray(void) const
Definition: cnxstring.hxx:174
const unsigned int getLength(void) const
Definition: cnxstring.hxx:325
const nxwidget_char_t getCharAt(int index) const
Definition: cnxstring.cxx:467
void copyToCharArray(FAR nxwidget_char_t *buffer) const
Definition: cnxstring.cxx:172
CStringIterator * newStringIterator(void) const
Definition: cnxstring.cxx:156
FAR nxwidget_char_t * m_text
Definition: cnxstring.hxx:133
void insert(const CNxString &text, const int index)
Definition: cnxstring.cxx:295
CNxString * subString(int startIndex) const
Definition: cnxstring.cxx:631