AceCommon
1.5.2
Arduino library for low-level common functions and features with no external dependencies
|
Base class for all template instances of the PrintStr<SIZE> class. More...
#include <PrintStr.h>
Public Member Functions | |
size_t | write (uint8_t c) override |
Write a single character into the internal buffer. | |
size_t | write (const uint8_t *buf, size_t size) override |
Write the buf string of size into the internal buffer. | |
void | flush () override |
Clear the internal buffer. More... | |
const char * | cstr () const |
Return the NUL terminated c-string buffer. More... | |
const char * | getCstr () const |
Backwards compatible version of cstr(). More... | |
size_t | length () const |
Return the length of the internal c-string buffer, not including the NUL terminator. | |
Protected Member Functions | |
PrintStrBase (uint16_t size, char *buf) | |
Constructor. More... | |
Protected Attributes | |
char *const | buf_ |
This is the pointer to the character array buffer. More... | |
Base class for all template instances of the PrintStr<SIZE> class.
A common base class reduces the code size because only one copy of the core code is included across all possible template instances. Otherwise, PrintStr<10> is a different class than PrintStr<20> and would pull in duplicate copies of the code.
Usually the Print
base class can be used to accept instances of the PrintStr<SIZE>
objects. However, if you need access to the length()
method, then you need to use the PrintStrBase
class instead, since the Print
class does not have a length()
method.
Here are the actual numbers. I modified tests/CommonTest.ino program to use 2 template instances, PrintStr<10> and PrintStr<20> instead of just PrintStr<10>. Without this base class optimization, the sketch uses:
After inserting this PrintStrBase class in the class hierarchy, the same sketch uses:
So we save 94 bytes of flash memory, and 12 bytes of static RAM. And even better, the program and RAM size was the same as using 2 PrintStr<10> instances. In other words, the amount of flash and static RAM remains constant no matter how many template instances we create.
Definition at line 63 of file PrintStr.h.
|
inlineprotected |
Constructor.
size | the maximum size of the given buf buffer |
buf | pointer to the character buffer created by the subclass. The buffer will be either on the stack or on the heap. |
Definition at line 163 of file PrintStr.h.
|
inline |
Return the NUL terminated c-string buffer.
After the buffer is no longer needed, the flush() method should be called to reset the internal buffer index to 0.
The cstr()
name was deliberately chosen to be different from the c_str()
method in the C++ std::string
class or the Arduino String
class. When we see an object being called with cstr()
, we can infer that its type is PrintStr
or PrintStrN
.
Definition at line 142 of file PrintStr.h.
|
inlineoverride |
Clear the internal buffer.
On most platforms (AVR, SAMD21, ESP8266, Teensy), the Print::flush() method is virtual, so this would normally be tagged with the 'override' keyword. But until recently, the ESP32 and STM32 platforms implemented the flush()
method as non-virtual methods. So I was forced to avoid marking this implementation with the override
keyword, which unfortunately triggered warning messages when compiled with clang++ compiler on Linux or MacOS using the EpoxyDuino environment.
The STM32 platform fixed this in v2.0.0 on 2021-04-21, and the ESP32 platform fixed this in v2.0.3 on 2022-05-04. I think we can finally assume that most platforms implement a virtual flush() and apply the override
keyword here, which also fixes the compiler warnings in EpoxyDuino.
The only platform that is officially supported by AceCommon where the override
will cause problems is the https://github.com/SpenceKonde/ATTinyCore platform whose Print
class does not implement flush()
at all. I have to make an exception for that Core, but there does not seem to be a single macro symbol that identifies the ATTinyCore. I have to enumerate each microcontroller type supported by that Core. Other platforms which also implement a non-virtual flush() can be listed in the exception list.
Definition at line 127 of file PrintStr.h.
|
inline |
Backwards compatible version of cstr().
New code should use cstr().
Definition at line 148 of file PrintStr.h.
|
protected |
This is the pointer to the character array buffer.
For instances of PrintStr<SIZE>
, this points to actualBuf_
which is created on the stack. For instances of PrintStrN
, it points to the char array allocated on the heap.
In the case of PrintStr
, there might be a way to remove this member variable by calculating the pointer to the stack buffer, by extending the pointer from the last element of this object (i.e. &index_), and thereby saving some memory.
But I am not convinced that I have the knowledge do that properly without triggering UB (undefined behavior) in the C++ language. Do I define buf_[0] here and will it point exactly where actualBuf_[] is allocated? Or do I use [&PrintStrBase + sizeof(PrintStrBase)] to calculate the pointer to actualBuf_. I just don't know what's actually allowed in the language spec versus something that works by pure luck on a particular microcontroller and compiler. So I'll pay the cost of the 2 extra bytes (8-bit) or 4 extra bytes (32-bit processors) of RAM and store the pointer to actualBuf_ explicitly here in the base class.
Definition at line 199 of file PrintStr.h.