AceCommon  1.4.6
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 #if ENABLE_SERIAL_DEBUG
6  #include "../print_utils/printfTo.h"
7 #endif
8 
9 namespace ace_common {
10 
11 int KString::compareTo(const char* s) {
12  #if ENABLE_SERIAL_DEBUG
13  Serial.println("compareTo()");
14  #endif
15  if (string_ == s) { return 0; }
16  if (string_ == nullptr) { return -1; }
17  if (s == nullptr) { return 1; }
18 
19  const char* a = (const char*) string_;
20  const char* b = s;
21  bool isCstring = (type_ == kTypeCstring);
22  while (true) {
23  uint8_t cb = *b;
24 
25  Restart:
26  // Extract the current character depending on the 'type_'. Normally doing a
27  // conditional check inside an inner loop is not good for performance.
28  // However, when I pulled this code out into a template function (using a
29  // thin-wrapper CString and FString), the AceTime/AutoBenchmark program
30  // showed that it made no perceptible difference in performance. I think
31  // this is because there is enough overhead in the rest of function to make
32  // this conditional code unimportant.
33  uint8_t ca = isCstring ? *a : pgm_read_byte(a);
34 
35  #if ENABLE_SERIAL_DEBUG
36  printfTo(Serial, "outer: a=%c b=%c", ca, cb);
37  Serial.println();
38  #endif
39  if (ca != cb) {
40  // If ca is a keyword reference, then compare against the keyword.
41  // Recursive keyword substitution not allowed, because I don't want to
42  // make this function recursive.
43  if (0 < ca && ca < numKeywords_) {
44  const char* k = keywords_[ca];
45  while (true) {
46  ca = *k;
47  cb = *b;
48  #if ENABLE_SERIAL_DEBUG
49  printfTo(Serial, "inner: a=%c b=%c", ca, cb);
50  Serial.println();
51  #endif
52  if (ca == '\0') {
53  a++;
54  // Terrible goto, but it's the easiest way to bail out of the inner
55  // loop and continue the outer loop at the correct character.
56  goto Restart;
57  }
58  if (ca != cb) {
59  return (int) ca - (int) cb;
60  }
61  k++;
62  b++;
63  }
64  } else {
65  return (int) ca - (int) cb;
66  }
67  }
68  if (ca == '\0') return 0;
69  a++;
70  b++;
71  }
72 }
73 
74 void KString::printTo(Print& printer) {
75  const char* s = (const char*) string_;
76  if (s == nullptr) return;
77 
78  bool isCstring = (type_ == kTypeCstring);
79  while (true) {
80  // Same comment as above, doing a conditional check inside an inner loop is
81  // usually not good for performance. But the templatized version of
82  // compareTo() made no difference, and this function which outputs to a
83  // Printer is not expected to be in a performance critical section.
84  char c = isCstring ? *s : pgm_read_byte(s);
85 
86  s++;
87  if (c == 0) break;
88  if (c < numKeywords_) {
89  printer.print(keywords_[(uint8_t) c]);
90  } else {
91  printer.write(c);
92  }
93  }
94 }
95 
96 } // ace_common
ace_common::KString::printTo
void printTo(Print &printer)
Expand and print the current string to the given printer.
Definition: KString.cpp:74
ace_common::printfTo
void printfTo(Print &printer, const char *fmt,...)
A printf() that works on an Arduino Print object using the built-in vsnprintf().
Definition: printfTo.h:59
ace_common::KString::compareTo
int compareTo(const char *s)
Compare this string against s and return <0, 0 or >0 if this string is less than, equal to,...
Definition: KString.cpp:11