CStringArray

Introduction

This is a class to manage a double NUL-terminated list of strings, such as "one\0two\0three\0".

It’s similar in operation to Vector<String>, but more memory-efficient as all the data is stored in a single String object. (CStringArray is a subclass of String.)

You can see some examples in Sming/Core/DateTime.cpp and Sming/Core/Data/WebConstants.cpp.

Background

Each value in the sequence is terminated by a NUL character \0. For clarity, placing one string per line is suggested:

// ["one", "two", "three"]
CStringArray csa = F(
   "one\0"
   "two\0"
   "three\0"
);

Note use of the F() macro. Assignments require a length because of the NUL characters, so this won’t work as expected:

// ["one"]
CStringArray csa =
   "one\0"
   "two\0"
   "three\0";

When assigning sequences, the final NUL separator may be omitted (it will be added automatically):

// ["one", "two", "three"]
CStringArray csa = F(
   "one\0"
   "two\0"
   "three"
);

Sequences may contain empty values, so this example contains four values:

// ["one", "two", "three", ""]
CStringArray csa = F(
   "one\0"
   "two\0"
   "three\0"
   "\0"
);

Adding strings

Elements can be added using standard concatenation operators:

CStringArray arr;
arr += "string1";
arr += 12;
arr += 5.4;
arr += F("data");

Be mindful that each call may require a heap re-allocation, so consider estimating or calculating the required space and using String::reserve():

CStringArray arr;
arr.reserve(250);
// now add content

Use with FlashString

You can use a single FlashString containing these values and load them all at the same time into a CStringArray:

DEFINE_FSTR_LOCAL(fstr_list,
   "a\0"
   "b\0"
   "c\0"
   "d\0"
   "e\0"
);

CStringArray list(fstr_list);
for(unsigned i = 0; i < list.count(); ++i) {
   debug_i("list[%u] = '%s'", i, list[i]);
}

Note

The entire FlashString is loaded into RAM so better suited for occasional lookups or if instantiated outside of a loop.

You may find FSTR::Array, FSTR::Vector or FSTR::Map more appropriate. See FlashString for details.

Iterator support

Looping by index is slow because the array must be scanned from the start for each access. Iterators are simpler to use and much more efficient:

for(auto s: list) {
   debug_i("'%s'", s);
}

For more complex operations:

CStringArray::Iterator pos;
for(auto it = list.begin(); it != list.end(); ++it) {
   debug_i("list[%u] = '%s' @ %u", it.index(), *it, it.offset());
   // Can use direct comparison with const char* or String
   if(it == "c") {
      pos = it; // Note position
   }
}

if(pos) {
   debug_i("Item '%s' found at index %u, offset %u", pos.str(), pos.index(), pos.offset());
} else {
   debug_i("Item not found");
}

Pushing and popping

CStringArray can be used as a simple FIFO or stack using push/pop methods. Behaviour is similar to STL deque, except pop methods also return a value.

STACK:

CStringArray csa;
csa.pushBack("first value");
csa.pushBack("second value");
String popStack = csa.popBack(); // "second value"

FIFO:

CStringArray csa;
csa.pushBack("first value");
csa.pushBack("second value");
String deque = csa.popFront(); // "first value"

Note that popping values does not perform any memory de-allocation.

Comparison with Vector<String>

Advantages

More memory efficient Uses only a single heap allocation (assuming content is passed to constructor) Useful for simple lookups, e.g. mapping enumerated values to strings

Disadvantages

Slower. Items must be iterated using multiple strlen() calls Ordering and insertions / deletions not supported

API Documentation

class CStringArray : private String

Class to manage a double null-terminated list of strings, such as “one\0two\0three\0”.

Concatenation operators

template<typename T>
inline CStringArray &operator+=(const T &value)

Append numbers, etc. to the array.

Parameters:

value – char, int, float, etc. as supported by String

Public Functions

inline String release()

Give up underlying String object to caller so it can be manipulated.

bool add(const char *str, int length = -1)

Append a new string (or array of strings) to the end of the array.

Note

If str contains any NUL characters it will be handled as an array

Parameters:
  • str

  • length – Length of new string in array (default is length of str)

Return values:

bool – false on memory allocation error

inline bool add(const String &str)

Append a new string (or array of strings) to the end of the array.

Note

If str contains any NUL characters it will be handled as an array

Parameters:

str

Return values:

bool – false on memory allocation error

int indexOf(const char *str, bool ignoreCase = true) const

Find the given string and return its index.

Note

Comparison is not case-sensitive

Parameters:
  • strString to find

  • ignoreCase – Whether search is case-sensitive or not

Return values:

int – index of given string, -1 if not found

inline int indexOf(const String &str, bool ignoreCase = true) const

Find the given string and return its index.

Note

Comparison is not case-sensitive

Parameters:
  • strString to find

  • ignoreCase – Whether search is case-sensitive or not

Return values:

int – index of given string, -1 if not found

inline bool contains(const char *str, bool ignoreCase = true) const

Check if array contains a string.

Note

Search is not case-sensitive

Parameters:
  • strString to search for

  • ignoreCase – Whether search is case-sensitive or not

Return values:

bool – True if string exists in array

inline bool contains(const String &str, bool ignoreCase = true) const

Check if array contains a string.

Note

Search is not case-sensitive

Parameters:
  • strString to search for

  • ignoreCase – Whether search is case-sensitive or not

Return values:

bool – True if string exists in array

const char *getValue(unsigned index) const

Get string at the given position.

Parameters:

index – 0-based index of string to obtain

Return values:

const – char* nullptr if index is not valid

inline const char *operator[](unsigned index) const

Get string at the given position.

Parameters:

index – 0-based index of string to obtain

Return values:

const – char* nullptr if index is not valid

inline const char *front() const

Get first value in array, null if empty.

bool pushFront(const char *str)

Insert item at start of array.

Parameters:

str – Item to insert

Return values:

bool – false on memory error

String popFront()

Pop first item from array (at index 0)

Return values:

String – null if array is empty

const char *back() const

Get last item in array, null if empty.

inline bool pushBack(const char *str)

Add item to end of array.

Parameters:

str – Item to add

Return values:

bool – false on memory error

String popBack()

Pop last item from array.

Return values:

String – null if array is empty

inline void clear()

Empty the array.

unsigned count() const

Get quantity of strings in array.

Return values:

unsigned – Quantity of strings

String join(const String &separator = ",") const

Get contents of array as delimited string.

Parameters:

separator – What to join elements with

Return values:

String – e.g. CStringArray(F(“a\0b\0c”)).join() returns “a,b,c”

bool reserve(size_t size)

Pre-allocate String memory.

On failure, the String is left unchanged. reserve(0), if successful, will validate an invalid string (i.e., “if (s)” will be true afterwards)

Parameters:

size

Return values:

bool – true on success, false on failure

inline const char *c_str() const

Get a constant (un-modifiable) pointer to String content.

Return values:

const – char* Always valid, even for a null string

bool endsWith(char suffix) const

Compare the end of a String.

Parameters:

suffix

Return values:

bool – true on match

bool endsWith(const String &suffix) const

Compare the end of a String.

Parameters:

suffix

Return values:

bool – true on match

size_t getBytes(unsigned char *buf, size_t bufsize, size_t index = 0) const

Read contents of a String into a buffer.

Note

Returned data always nul terminated so buffer size needs to take this into account

Parameters:
  • buf – buffer to write data

  • bufsize – size of buffer in bytes

  • index – offset to start

Return values:

unsigned – number of bytes copied, excluding nul terminator

inline size_t length(void) const

Obtain the String length in characters, excluding NUL terminator.

inline bool startsWith(const String &prefix) const

Compare the start of a String Comparison is case-sensitive, must match exactly.

Parameters:

prefix

Return values:

bool – true on match

bool startsWith(const String &prefix, size_t offset) const

Compare a string portion.

mis-named as does not necessarily compare from start

Note

Comparison is case-sensitive, must match exactly

Parameters:
  • prefix

  • offset – Index to start comparison at

Return values:

bool – true on match

inline void toCharArray(char *buf, size_t bufsize, size_t index = 0) const

Read contents of String into a buffer.

See also

See getBytes()

void toLowerCase(void)

Convert the entire String content to lower case.

void toUpperCase(void)

Convert the entire String content to upper case.

class Iterator