From ff9a16a41bb6298265daf2a71118f14329b8b2e4 Mon Sep 17 00:00:00 2001 From: Greg Mrozek Date: Fri, 2 Nov 2018 09:13:44 -0500 Subject: [PATCH] Add FlashString abstract class to support extension of String and Print methods to core specific program memory implementation. --- api/Print.cpp | 42 ++------- api/Print.h | 4 +- api/String.cpp | 38 ++------ api/String.h | 39 +++++--- api/deprecated-avr-comp/avr/pgmspace.h | 122 ------------------------- 5 files changed, 45 insertions(+), 200 deletions(-) delete mode 100644 api/deprecated-avr-comp/avr/pgmspace.h diff --git a/api/Print.cpp b/api/Print.cpp index 4f0016c4..7938e9d3 100644 --- a/api/Print.cpp +++ b/api/Print.cpp @@ -36,23 +36,6 @@ size_t Print::write(const uint8_t *buffer, size_t size) return n; } -size_t Print::print(const __FlashStringHelper *ifsh) -{ -#if defined(__AVR__) - PGM_P p = reinterpret_cast(ifsh); - size_t n = 0; - while (1) { - unsigned char c = pgm_read_byte(p++); - if (c == 0) break; - if (write(c)) n++; - else break; - } - return n; -#else - return print(reinterpret_cast(ifsh)); -#endif -} - size_t Print::print(const String &s) { return write(s.c_str(), s.length()); @@ -132,13 +115,6 @@ size_t Print::print(double n, int digits) return printFloat(n, digits); } -size_t Print::println(const __FlashStringHelper *ifsh) -{ - size_t n = print(ifsh); - n += println(); - return n; -} - size_t Print::print(const Printable& x) { return x.printTo(*this); @@ -330,15 +306,15 @@ size_t Print::printULLNumber(unsigned long long n64, uint8_t base) return bytes; } -size_t Print::printFloat(double number, uint8_t digits) -{ +size_t Print::printFloat(double number, uint8_t digits) +{ size_t n = 0; - + if (isnan(number)) return print("nan"); if (isinf(number)) return print("inf"); if (number > 4294967040.0) return print ("ovf"); // constant determined empirically if (number <-4294967040.0) return print ("ovf"); // constant determined empirically - + // Handle negative numbers if (number < 0.0) { @@ -350,7 +326,7 @@ size_t Print::printFloat(double number, uint8_t digits) double rounding = 0.5; for (uint8_t i=0; i 0) { - n += print("."); + n += print('.'); } // Extract digits from the remainder one at a time @@ -369,8 +345,8 @@ size_t Print::printFloat(double number, uint8_t digits) remainder *= 10.0; unsigned int toPrint = (unsigned int)remainder; n += print(toPrint); - remainder -= toPrint; - } - + remainder -= toPrint; + } + return n; } diff --git a/api/Print.h b/api/Print.h index 6a06bad6..4e435046 100644 --- a/api/Print.h +++ b/api/Print.h @@ -53,8 +53,7 @@ class Print size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } - - size_t print(const __FlashStringHelper *); + size_t print(const String &); size_t print(const char[]); size_t print(char); @@ -68,7 +67,6 @@ class Print size_t print(double, int = 2); size_t print(const Printable&); - size_t println(const __FlashStringHelper *); size_t println(const String &s); size_t println(const char[]); size_t println(char); diff --git a/api/String.cpp b/api/String.cpp index 5eb0b2a2..22f8369c 100644 --- a/api/String.cpp +++ b/api/String.cpp @@ -39,10 +39,10 @@ String::String(const String &value) *this = value; } -String::String(const __FlashStringHelper *pstr) +String::String(const FlashString &fstr) { - init(); - *this = pstr; + init(); + *this = fstr; } #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) @@ -180,17 +180,6 @@ String & String::copy(const char *cstr, unsigned int length) return *this; } -String & String::copy(const __FlashStringHelper *pstr, unsigned int length) -{ - if (!reserve(length)) { - invalidate(); - return *this; - } - len = length; - strcpy_P(buffer, (PGM_P)pstr); - return *this; -} - #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) void String::move(String &rhs) { @@ -245,11 +234,9 @@ String & String::operator = (const char *cstr) return *this; } -String & String::operator = (const __FlashStringHelper *pstr) +String & String::operator = (const FlashString &fstr) { - if (pstr) copy(pstr, strlen_P((PGM_P)pstr)); - else invalidate(); - + *this = fstr.toString(); return *this; } @@ -336,16 +323,9 @@ unsigned char String::concat(double num) return concat(string, strlen(string)); } -unsigned char String::concat(const __FlashStringHelper * str) +unsigned char String::concat(const FlashString &fstr) { - if (!str) return 0; - int length = strlen_P((const char *) str); - if (length == 0) return 1; - unsigned int newlen = len + length; - if (!reserve(newlen)) return 0; - strcpy_P(buffer + len, (const char *) str); - len = newlen; - return 1; + return concat(fstr.toString()); } /*********************************************/ @@ -422,7 +402,7 @@ StringSumHelper & operator + (const StringSumHelper &lhs, double num) return a; } -StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs) +StringSumHelper & operator + (const StringSumHelper &lhs, const FlashString &rhs) { StringSumHelper &a = const_cast(lhs); if (!a.concat(rhs)) a.invalidate(); @@ -592,7 +572,7 @@ int String::lastIndexOf(const String &s2) const int String::lastIndexOf(const String &s2, unsigned int fromIndex) const { - if (s2.len == 0 || len == 0 || s2.len > len) return -1; + if (s2.len == 0 || len == 0 || s2.len > len) return -1; if (fromIndex >= len) fromIndex = len - 1; int found = -1; for (char *p = buffer; p <= buffer + fromIndex; p++) { diff --git a/api/String.h b/api/String.h index 8c6d2d39..5d3183c5 100644 --- a/api/String.h +++ b/api/String.h @@ -23,14 +23,11 @@ #ifdef __cplusplus +#include "Printable.h" + #include #include #include -#if defined(__AVR__) -#include "avr/pgmspace.h" -#else -#include "deprecated-avr-comp/avr/pgmspace.h" -#endif // When compiling programs with this class, the following gcc parameters // dramatically increase performance and memory (RAM) efficiency, typically @@ -38,8 +35,25 @@ // -felide-constructors // -std=c++0x -class __FlashStringHelper; -#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) +class String; + +// Default implemtation of 'F' macro for cores than can use +// string literals directly as (const char *). +// For cores that require special interface to program memory, +// the default 'F' macro can be undefined at core +// implementation level and redefined as needed. +#define F(string_literal) (string_literal) + +// Base Class for strings stored in program memory. +// For cores that require special interface to program memory, +// this class can be extended at the core implementation +// level in order to support String and Print operations from +// program memory. +class FlashString : public Printable +{ + public: + virtual String toString() const = 0; +}; // An inherited class for holding the result of a concatenation. These // result objects are assumed to be writable by subsequent concatenations. @@ -62,7 +76,7 @@ class String // be false). String(const char *cstr = ""); String(const String &str); - String(const __FlashStringHelper *str); + String(const FlashString &fstr); #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String(String &&rval); String(StringSumHelper &&rval); @@ -89,7 +103,7 @@ class String // marked as invalid ("if (s)" will be false). String & operator = (const String &rhs); String & operator = (const char *cstr); - String & operator = (const __FlashStringHelper *str); + String & operator = (const FlashString &fstr); #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String & operator = (String &&rval); String & operator = (StringSumHelper &&rval); @@ -110,7 +124,7 @@ class String unsigned char concat(unsigned long num); unsigned char concat(float num); unsigned char concat(double num); - unsigned char concat(const __FlashStringHelper * str); + unsigned char concat(const FlashString &fstr); // if there's not enough memory for the concatenated value, the string // will be left unchanged (but this isn't signalled in any way) @@ -124,7 +138,7 @@ class String String & operator += (unsigned long num) {concat(num); return (*this);} String & operator += (float num) {concat(num); return (*this);} String & operator += (double num) {concat(num); return (*this);} - String & operator += (const __FlashStringHelper *str){concat(str); return (*this);} + String & operator += (const FlashString &fstr){concat(fstr); return (*this);} friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); @@ -136,7 +150,7 @@ class String friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); friend StringSumHelper & operator + (const StringSumHelper &lhs, float num); friend StringSumHelper & operator + (const StringSumHelper &lhs, double num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const FlashString &rhs); // comparison (only works w/ Strings and "strings") operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } @@ -222,7 +236,6 @@ class String // copy and move String & copy(const char *cstr, unsigned int length); - String & copy(const __FlashStringHelper *pstr, unsigned int length); #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) void move(String &rhs); #endif diff --git a/api/deprecated-avr-comp/avr/pgmspace.h b/api/deprecated-avr-comp/avr/pgmspace.h deleted file mode 100644 index 0f732bba..00000000 --- a/api/deprecated-avr-comp/avr/pgmspace.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - pgmspace.h - Definitions for compatibility with AVR pgmspace macros - - Copyright (c) 2015 Arduino LLC - - Based on work of Paul Stoffregen on Teensy 3 (http://pjrc.com) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE -*/ - -#ifndef __PGMSPACE_H_ -#define __PGMSPACE_H_ 1 - -#include - -#define PROGMEM -#define PGM_P const char * -#define PSTR(str) (str) - -#define _SFR_BYTE(n) (n) - -typedef void prog_void; -typedef char prog_char; -typedef unsigned char prog_uchar; -typedef int8_t prog_int8_t; -typedef uint8_t prog_uint8_t; -typedef int16_t prog_int16_t; -typedef uint16_t prog_uint16_t; -typedef int32_t prog_int32_t; -typedef uint32_t prog_uint32_t; -typedef int64_t prog_int64_t; -typedef uint64_t prog_uint64_t; - -typedef const void* int_farptr_t; -typedef const void* uint_farptr_t; - -#define memchr_P(s, c, n) memchr((s), (c), (n)) -#define memcmp_P(s1, s2, n) memcmp((s1), (s2), (n)) -#define memccpy_P(dest, src, c, n) memccpy((dest), (src), (c), (n)) -#define memcpy_P(dest, src, n) memcpy((dest), (src), (n)) -#define memmem_P(haystack, haystacklen, needle, needlelen) memmem((haystack), (haystacklen), (needle), (needlelen)) -#define memrchr_P(s, c, n) memrchr((s), (c), (n)) -#define strcat_P(dest, src) strcat((dest), (src)) -#define strchr_P(s, c) strchr((s), (c)) -#define strchrnul_P(s, c) strchrnul((s), (c)) -#define strcmp_P(a, b) strcmp((a), (b)) -#define strcpy_P(dest, src) strcpy((dest), (src)) -#define strcasecmp_P(s1, s2) strcasecmp((s1), (s2)) -#define strcasestr_P(haystack, needle) strcasestr((haystack), (needle)) -#define strcspn_P(s, accept) strcspn((s), (accept)) -#define strlcat_P(s1, s2, n) strlcat((s1), (s2), (n)) -#define strlcpy_P(s1, s2, n) strlcpy((s1), (s2), (n)) -#define strlen_P(a) strlen((a)) -#define strnlen_P(s, n) strnlen((s), (n)) -#define strncmp_P(s1, s2, n) strncmp((s1), (s2), (n)) -#define strncasecmp_P(s1, s2, n) strncasecmp((s1), (s2), (n)) -#define strncat_P(s1, s2, n) strncat((s1), (s2), (n)) -#define strncpy_P(s1, s2, n) strncpy((s1), (s2), (n)) -#define strpbrk_P(s, accept) strpbrk((s), (accept)) -#define strrchr_P(s, c) strrchr((s), (c)) -#define strsep_P(sp, delim) strsep((sp), (delim)) -#define strspn_P(s, accept) strspn((s), (accept)) -#define strstr_P(a, b) strstr((a), (b)) -#define strtok_P(s, delim) strtok((s), (delim)) -#define strtok_rP(s, delim, last) strtok((s), (delim), (last)) - -#define strlen_PF(a) strlen((a)) -#define strnlen_PF(src, len) strnlen((src), (len)) -#define memcpy_PF(dest, src, len) memcpy((dest), (src), (len)) -#define strcpy_PF(dest, src) strcpy((dest), (src)) -#define strncpy_PF(dest, src, len) strncpy((dest), (src), (len)) -#define strcat_PF(dest, src) strcat((dest), (src)) -#define strlcat_PF(dest, src, len) strlcat((dest), (src), (len)) -#define strncat_PF(dest, src, len) strncat((dest), (src), (len)) -#define strcmp_PF(s1, s2) strcmp((s1), (s2)) -#define strncmp_PF(s1, s2, n) strncmp((s1), (s2), (n)) -#define strcasecmp_PF(s1, s2) strcasecmp((s1), (s2)) -#define strncasecmp_PF(s1, s2, n) strncasecmp((s1), (s2), (n)) -#define strstr_PF(s1, s2) strstr((s1), (s2)) -#define strlcpy_PF(dest, src, n) strlcpy((dest), (src), (n)) -#define memcmp_PF(s1, s2, n) memcmp((s1), (s2), (n)) - -#define sprintf_P(s, f, ...) sprintf((s), (f), __VA_ARGS__) -#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__) - -#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) -#define pgm_read_word(addr) (*(const unsigned short *)(addr)) -#define pgm_read_dword(addr) (*(const unsigned long *)(addr)) -#define pgm_read_float(addr) (*(const float *)(addr)) -#define pgm_read_ptr(addr) (*(const void *)(addr)) - -#define pgm_read_byte_near(addr) pgm_read_byte(addr) -#define pgm_read_word_near(addr) pgm_read_word(addr) -#define pgm_read_dword_near(addr) pgm_read_dword(addr) -#define pgm_read_float_near(addr) pgm_read_float(addr) -#define pgm_read_ptr_near(addr) pgm_read_ptr(addr) - -#define pgm_read_byte_far(addr) pgm_read_byte(addr) -#define pgm_read_word_far(addr) pgm_read_word(addr) -#define pgm_read_dword_far(addr) pgm_read_dword(addr) -#define pgm_read_float_far(addr) pgm_read_float(addr) -#define pgm_read_ptr_far(addr) pgm_read_ptr(addr) - -#define pgm_get_far_address(addr) (&(addr)) - -#endif