AceCommon  1.6.0
Arduino library for low-level common functions and features with no external dependencies
KString.cpp
1 #include <Arduino.h>
2 #include <string.h>
3 #include "KString.h"
4 
5 namespace ace_common {
6 
7 int KString::compareTo(const char* s) {
8  if (string_ == s) { return 0; }
9  if (string_ == nullptr) { return -1; }
10  if (s == nullptr) { return 1; }
11 
12  const char* a = (const char*) string_;
13  const char* b = s;
14  while (true) {
15  uint8_t cb = *b;
16 
17  Restart:
18  // Extract the current character depending on the 'type_'. Normally doing a
19  // conditional check inside an inner loop is not good for performance.
20  // However, when I pulled this code out into a template function (using a
21  // thin-wrapper CString and FString), the AceTime/AutoBenchmark program
22  // showed that it made no perceptible difference in performance. I think
23  // this is because there is enough overhead in the rest of function to make
24  // this conditional code unimportant.
25  uint8_t ca = (type_ == kTypeCstring) ? *a : pgm_read_byte(a);
26 
27  if (ca != cb) {
28  // If ca is a keyword reference, then compare against the keyword.
29  // Recursive keyword substitution not allowed, because I don't want to
30  // make this function recursive.
31  if (0 < ca && ca < numKeywords_) {
32  KStringKeywords keywords(type_, keywords_);
33  const char* k = keywords.get(ca);
34  while (true) {
35  ca = (type_ == kTypeCstring) ? *k : pgm_read_byte(k);
36  cb = *b;
37  if (ca == '\0') {
38  a++;
39  // Terrible goto, but it's the easiest way to bail out of the inner
40  // loop and continue the outer loop at the correct character.
41  goto Restart;
42  }
43  if (ca != cb) {
44  return (int) ca - (int) cb;
45  }
46  k++;
47  b++;
48  }
49  } else {
50  return (int) ca - (int) cb;
51  }
52  }
53  if (ca == '\0') return 0;
54  a++;
55  b++;
56  }
57 }
58 
59 int KString::compareTo(const KString& s) {
60  if (this == &s) { return 0; }
61  if (string_ == s.string_) { return 0; }
62  if (string_ == nullptr) { return -1; }
63  if (s.string_ == nullptr) { return 1; }
64 
65  KStringIterator aiter(*this);
66  KStringIterator biter(s);
67  while (true) {
68  char ca = aiter.get();
69  char cb = biter.get();
70 
71  if (ca == cb) {
72  if (ca == '\0') {
73  return 0;
74  }
75  } else {
76  return ca - cb;
77  }
78  aiter.next();
79  biter.next();
80  }
81 }
82 
83 void KString::printTo(Print& printer) {
84  const char* s = (const char*) string_;
85  if (s == nullptr) return;
86 
87  while (true) {
88  // Same comment as above, doing a conditional check inside an inner loop is
89  // usually not good for performance. But the templatized version of
90  // compareTo() made no difference, and this function which outputs to a
91  // Printer is not expected to be in a performance critical section.
92  char c = (type_ == kTypeCstring) ? *s : pgm_read_byte(s);
93 
94  s++;
95  if (c == 0) break;
96  if (c < numKeywords_) {
97  if (type_ == kTypeCstring) {
98  printer.print((const char*) keywords_[(uint8_t) c]);
99  } else {
100  printer.print((const __FlashStringHelper*)
101  pgm_read_ptr(keywords_ + (uint8_t) c));
102  }
103  } else {
104  printer.write(c);
105  }
106  }
107 }
108 
110  // We don't support recursive compression fragments (i.e. compress tokens
111  // within fragments) so this does NOT need to be a loop.
112  char c = getInternal(ks_.type_, firstPtr_);
113  if (c == '\0') {
114  if (secondPtr_ != nullptr) {
115  // pop the stack
116  firstPtr_ = secondPtr_;
117  secondPtr_ = nullptr;
118 
119  // advance one character
120  firstPtr_++;
121  c = getInternal(ks_.type_, firstPtr_);
122  }
123  }
124 
125  if (c != '\0' && c < 0x20) { // fragment keyword string
126  // push the stack
127  secondPtr_ = firstPtr_;
128  KStringKeywords keywords(ks_.type_, ks_.keywords_);
129  firstPtr_ = keywords.get((uint8_t) c);
130  c = getInternal(ks_.type_, firstPtr_);
131  }
132 
133  return c;
134 }
135 
136 } // ace_common
An interator that points to a character inside a KString.
Definition: KString.h:135
void next()
Advance the iterator one character,.
Definition: KString.h:156
char get()
Return the current character referenced by the iterator.
Definition: KString.cpp:109
A thin helper object around an array of const char* in regular memory, or an array of const __FlashSt...
Definition: KString.h:175
const char * get(uint8_t i) const
Return the string pointer of index i.
Definition: KString.h:193
A wrapper class around a normal c-string or Arduino f-string which is encoded and compressed using ke...
Definition: KString.h:53
void printTo(Print &printer)
Expand and print the current string to the given printer.
Definition: KString.cpp:83
int compareTo(const char *s)
Compare this string against a c-string s and return <0, 0 or >0 if this string is <,...
Definition: KString.cpp:7