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/Network/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");
}

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

An example of use can be found in Sming/Core/Network/Http/HttpHeaders.h.

API Documentation

class CStringArray : String

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

Constructors

CStringArray(const String &str)
CStringArray(const char *cstr = nullptr)
CStringArray(const char *cstr, unsigned int length)
CStringArray(flash_string_t pstr, int length = -1)
CStringArray(const FlashString &fstr)

Concatenation operators

CStringArray &operator+=(const String &str)
CStringArray &operator+=(const char *cstr)
template <typename T>
CStringArray &operator+=(T value)

Append numbers, etc. to the array.

Parameters
  • value: char, int, float, etc. as supported by String

Iterator support (forward only)

Iterator begin() const
Iterator end() const

Concatenation methods

Works with built-in types. On failure, the string is left unchanged. If the argument is null or invalid, the concatenation is considered unsucessful.

Return Value
  • bool: true on success, false on failure

bool concat(const String &str)
bool concat(const FlashString &fstr)
bool concat(const char *cstr)
bool concat(const char *cstr, size_t length)
bool concat(char c)
bool concat(unsigned char num)
bool concat(int num)
bool concat(unsigned int num)
bool concat(long num)
bool concat(long long num)
bool concat(unsigned long num)
bool concat(unsigned long long num)
bool concat(float num)
bool concat(double num)

Concatenation operators

If there’s not enough memory for the concatenated value, the string will be left unchanged (but this isn’t signalled in any way)

String &operator+=(const FlashString &rhs)
String &operator+=(char c)
String &operator+=(unsigned char num)
String &operator+=(int num)
String &operator+=(unsigned int num)
String &operator+=(long num)
String &operator+=(long long num)
String &operator+=(unsigned long num)
String &operator+=(unsigned long long num)
String &operator+=(float num)
String &operator+=(double num)

Comparison methods

Works with String and ‘c’ string

Comparisons are case-sensitive, binary comparison null strings (including cstr == nullptr) are treated as empty.

Return Value
  • int: Returns < 0 if String is lexically before the argument, > 0 if after or 0 if the same

int compareTo(const char *cstr, size_t length) const
int compareTo(const String &s) const

Test for equality

Compares content byte-for-byte using binary comparison

null strings (including cstr == nullptr) are treated as empty.

Return Value
  • bool: Returns true if strings are identical

bool equals(const String &s) const
bool equals(const char *cstr) const
bool equals(const char *cstr, size_t length) const
bool equals(const FlashString &fstr) const

Equality operator ==

Return Value
  • bool: true if Strings are identical

bool operator==(const String &rhs) const
bool operator==(const char *cstr) const
bool operator==(const FlashString &fstr) const

In-equality operator !=

Return Value
  • bool: Returns true if strings are not identical

bool operator!=(const String &rhs) const
bool operator!=(const char *cstr) const

Comparison operators

bool operator<(const String &rhs) const
bool operator>(const String &rhs) const
bool operator<=(const String &rhs) const
bool operator>=(const String &rhs) const

Test for equality, without case-sensitivity

null strings are treated as empty.

Return Value
  • bool: true if strings are considered the same

bool equalsIgnoreCase(const char *cstr) const
bool equalsIgnoreCase(const char *cstr, size_t length) const
bool equalsIgnoreCase(const String &s2) const
bool equalsIgnoreCase(const FlashString &fstr) const

Array operators

If index is invalid, returns NUL \0

char operator[](size_t index) const
char &operator[](size_t index)

int indexOf(…)

Locate a character or String within another String.

By default, searches from the beginning of the

String, but can also start from a given index, allowing for the locating of all instances of the character or String.
Return Value
  • int: Index if found, -1 if not found

int indexOf(char ch, size_t fromIndex = 0) const
int indexOf(const char *s2_buf, size_t fromIndex, size_t s2_len) const
int indexOf(const char *s2_buf, size_t fromIndex = 0) const
int indexOf(const String &s2, size_t fromIndex = 0) const

int lastIndexOf(…)

Locate a character or String within another String

By default, searches from the end of the

String, but can also work backwards from a given index, allowing for the locating of all instances of the character or String.
Return Value
  • int: Index if found, -1 if not found

int lastIndexOf(char ch) const
int lastIndexOf(char ch, size_t fromIndex) const
int lastIndexOf(const String &s2) const
int lastIndexOf(const String &s2, size_t fromIndex) const
int lastIndexOf(const char *s2_buf, size_t fromIndex, size_t s2_len) const

String substring(…)

Get a substring of a String.

The starting index is inclusive (the corresponding character is included in the substring), but the optional ending index is exclusive (the corresponding character is not included in the substring).

Parameters
  • from: Index of first character to retrieve
  • to: (optional) One-past the ending character to retrieve

If the ending index is omitted, the substring continues to the end of the String.

If you don’t need the original String, consider using remove() instead:

    String original("This is the original string.");
    String sub = original.substring(0, 13);

This produces the same result:

    original.remove(13);

String substring(size_t from, size_t to) const
String substring(size_t from) const

replace(…)

Replace all instances of a given character or substring with another character or substring.

Replacing a single character always succeeds as this is handled in-place.

Return Value
  • bool: true on success, false on allocation failure

Where replace is longer than find the String may need to be re-allocated, which could fail. If this happens the method returns false and the String is left unchanged.

void replace(char find, char replace)
bool replace(const String &find, const String &replace)
bool replace(const char *find_buf, size_t find_len, const char *replace_buf, size_t replace_len)

remove()

Remove characters from a String.

If no count is provided then all characters from the given index to the end of the

String are removed.
Note
The String is modified in-situ without any reallocation
Parameters
  • index: Index of the first character to remove
  • count: Number of characters to remove

void remove(size_t index)
void remove(size_t index, size_t count)

Public Functions

CStringArray &operator=(const char *cstr)
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 Value
  • bool: false on memory allocation error

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 Value
  • 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
  • str: String to find
  • ignoreCase: Whether search is case-sensitive or not
Return Value
  • int: index of given string, -1 if not found

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

Find the given string and return its index.

Note
Comparison is not case-sensitive
Parameters
  • str: String to find
  • ignoreCase: Whether search is case-sensitive or not
Return Value
  • int: index of given string, -1 if not found

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

Check if array contains a string.

Note
Search is not case-sensitive
Parameters
  • str: String to search for
  • ignoreCase: Whether search is case-sensitive or not
Return Value
  • bool: True if string exists in array

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

Check if array contains a string.

Note
Search is not case-sensitive
Parameters
  • str: String to search for
  • ignoreCase: Whether search is case-sensitive or not
Return Value
  • 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 Value
  • const: char* nullptr if index is not valid

const char *operator[](unsigned index) const

Get string at the given position.

Parameters
  • index: 0-based index of string to obtain
Return Value
  • const: char* nullptr if index is not valid

void clear()

Empty the array.

unsigned count() const

Get quantity of strings in array.

Return Value
  • unsigned: Quantity of strings

Private Functions

void setString(const char *cstr, int length = -1)
void setString(flash_string_t pstr, int length = -1)
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 Value
  • bool: true on success, false on failure

bool setLength(size_t length)

set the string length accordingly, expanding if necessary

Note
extra characters are undefined
Parameters
  • length: required for string (nul terminator additional)
Return Value
  • true: on success, false on failure

size_t length(void) const

Obtain the String length in characters, excluding NUL terminator.

operator StringIfHelperType() const

Provides safe bool() operator.

Evaluates as false if String is null, otherwise evaluates as true

bool startsWith(const String &prefix) const

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

Parameters
  • prefix:
Return Value
  • 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 Value
  • bool: true on match

bool endsWith(const String &suffix) const

Compare the end of a String.

Parameters
  • suffix:
Return Value
  • bool: true on match

char charAt(size_t index) const

Obtain the character at the given index.

Note
If index is invalid, returns NUL \0
Parameters
  • index:
Return Value
  • char:

void setCharAt(size_t index, char c)

Sets the character at a given index.

Note
If index is invalid, does nothing
Parameters
  • index:
  • c:

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 Value
  • unsigned: number of bytes copied, excluding nul terminator

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

Read contents of String into a buffer.

See
See getBytes()

const char *c_str() const

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

Return Value
  • const: char* Always valid, even for a null string

char *begin()

Get a modifiable pointer to String content.

Note
If String is NUL, returns nullptr.

char *end()

Get a modifiable pointer to one-past the end of the String.

Note
Points to the terminating NUL character. If String is NUL, returns nullptr.

void toLowerCase(void)

Convert the entire String content to lower case.

void toUpperCase(void)

Convert the entire String content to upper case.

void trim(void)

Remove all leading and trailing whitespace characters from the String.

long toInt(void) const
float toFloat(void) const

Private Members

PtrBuf ptr
SsoBuf sso

Private Static Attributes

const String nullstr

A null string evaluates to false.

const String empty

An empty string evaluates to true.

constexpr size_t SSO_CAPACITY = STRING_OBJECT_SIZE - 2

Max chars. (excluding NUL terminator) we can store in SSO mode.

class Iterator

Public Types

using const_iterator = Iterator

Public Functions

Iterator()
Iterator(const Iterator&)
Iterator(const CStringArray *array, uint16_t offset, uint16_t index)
operator bool() const
bool equals(const char *rhs) const
bool equalsIgnoreCase(const char *rhs) const
bool operator==(const Iterator &rhs) const
bool operator!=(const Iterator &rhs) const
bool operator==(const char *rhs) const
bool operator!=(const char *rhs) const
bool equals(const String &rhs) const
bool equalsIgnoreCase(const String &rhs) const
bool operator==(const String &rhs) const
bool operator!=(const String &rhs) const
const char *str() const
const char *operator*() const
uint16_t index() const
uint16_t offset() const
Iterator &operator++()
Iterator operator++(int)
void next()