Copy ESP8266 String w/SSO to ESP32 repo (#2715)
I redid the ESP8266 WString library to enable small string optimization (SSO) a while back, and think it would be helpful even on the ESP32 with its higher memory complement. SSO avoids lots of tiny mallocs() on the heap which cause fragmentation by using the memory in the class object itself to store the actual string and only mallocing() for buffers that are larger than what can fit in thie class object. Modern C++ std::string implementations have this optimization as well, but since we're using Arduino strings we had to roll our own.
This commit is contained in:
parent
932666a03f
commit
ab309e40d5
@ -2,6 +2,7 @@
|
|||||||
StreamString.cpp
|
StreamString.cpp
|
||||||
|
|
||||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
@ -22,31 +23,27 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "StreamString.h"
|
#include "StreamString.h"
|
||||||
|
|
||||||
size_t StreamString::write(const uint8_t *data, size_t size)
|
size_t StreamString::write(const uint8_t *data, size_t size) {
|
||||||
{
|
|
||||||
if(size && data) {
|
if(size && data) {
|
||||||
if(reserve(length() + size + 1)) {
|
if(reserve(length() + size + 1)) {
|
||||||
memcpy((void *) (buffer + len), (const void *) data, size);
|
memcpy((void *) (wbuffer() + len()), (const void *) data, size);
|
||||||
len += size;
|
setLen(len() + size);
|
||||||
*(buffer + len) = 0x00; // add null for string end
|
*(wbuffer() + len()) = 0x00; // add null for string end
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t StreamString::write(uint8_t data)
|
size_t StreamString::write(uint8_t data) {
|
||||||
{
|
|
||||||
return concat((char) data);
|
return concat((char) data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamString::available()
|
int StreamString::available() {
|
||||||
{
|
|
||||||
return length();
|
return length();
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamString::read()
|
int StreamString::read() {
|
||||||
{
|
|
||||||
if(length()) {
|
if(length()) {
|
||||||
char c = charAt(0);
|
char c = charAt(0);
|
||||||
remove(0, 1);
|
remove(0, 1);
|
||||||
@ -56,8 +53,7 @@ int StreamString::read()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StreamString::peek()
|
int StreamString::peek() {
|
||||||
{
|
|
||||||
if(length()) {
|
if(length()) {
|
||||||
char c = charAt(0);
|
char c = charAt(0);
|
||||||
return c;
|
return c;
|
||||||
@ -65,7 +61,6 @@ int StreamString::peek()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamString::flush()
|
void StreamString::flush() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -35,17 +35,16 @@ class StringSumHelper;
|
|||||||
// an abstract class used as a means to proide a unique pointer type
|
// an abstract class used as a means to proide a unique pointer type
|
||||||
// but really has no body
|
// but really has no body
|
||||||
class __FlashStringHelper;
|
class __FlashStringHelper;
|
||||||
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
|
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
|
||||||
|
#define F(string_literal) (FPSTR(PSTR(string_literal)))
|
||||||
|
|
||||||
// The string class
|
// The string class
|
||||||
class String
|
class String {
|
||||||
{
|
|
||||||
// use a function pointer to allow for "if (s)" without the
|
// use a function pointer to allow for "if (s)" without the
|
||||||
// complications of an operator bool(). for more information, see:
|
// complications of an operator bool(). for more information, see:
|
||||||
// http://www.artima.com/cppsource/safebool.html
|
// http://www.artima.com/cppsource/safebool.html
|
||||||
typedef void (String::*StringIfHelperType)() const;
|
typedef void (String::*StringIfHelperType)() const;
|
||||||
void StringIfHelper() const
|
void StringIfHelper() const {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -56,7 +55,7 @@ public:
|
|||||||
// be false).
|
// be false).
|
||||||
String(const char *cstr = "");
|
String(const char *cstr = "");
|
||||||
String(const String &str);
|
String(const String &str);
|
||||||
String(const __FlashStringHelper *str) : String(reinterpret_cast<const char *>(str)) {};
|
String(const __FlashStringHelper *str);
|
||||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||||
String(String &&rval);
|
String(String &&rval);
|
||||||
String(StringSumHelper &&rval);
|
String(StringSumHelper &&rval);
|
||||||
@ -76,10 +75,9 @@ public:
|
|||||||
// is left unchanged). reserve(0), if successful, will validate an
|
// is left unchanged). reserve(0), if successful, will validate an
|
||||||
// invalid string (i.e., "if (s)" will be true afterwards)
|
// invalid string (i.e., "if (s)" will be true afterwards)
|
||||||
unsigned char reserve(unsigned int size);
|
unsigned char reserve(unsigned int size);
|
||||||
inline unsigned int length(void) const
|
inline unsigned int length(void) const {
|
||||||
{
|
if(buffer()) {
|
||||||
if(buffer) {
|
return len();
|
||||||
return len;
|
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -115,58 +113,47 @@ public:
|
|||||||
|
|
||||||
// if there's not enough memory for the concatenated value, the string
|
// if there's not enough memory for the concatenated value, the string
|
||||||
// will be left unchanged (but this isn't signalled in any way)
|
// will be left unchanged (but this isn't signalled in any way)
|
||||||
String & operator +=(const String &rhs)
|
String & operator +=(const String &rhs) {
|
||||||
{
|
|
||||||
concat(rhs);
|
concat(rhs);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(const char *cstr)
|
String & operator +=(const char *cstr) {
|
||||||
{
|
|
||||||
concat(cstr);
|
concat(cstr);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(char c)
|
String & operator +=(char c) {
|
||||||
{
|
|
||||||
concat(c);
|
concat(c);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(unsigned char num)
|
String & operator +=(unsigned char num) {
|
||||||
{
|
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(int num)
|
String & operator +=(int num) {
|
||||||
{
|
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(unsigned int num)
|
String & operator +=(unsigned int num) {
|
||||||
{
|
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(long num)
|
String & operator +=(long num) {
|
||||||
{
|
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(unsigned long num)
|
String & operator +=(unsigned long num) {
|
||||||
{
|
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(float num)
|
String & operator +=(float num) {
|
||||||
{
|
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator +=(double num)
|
String & operator +=(double num) {
|
||||||
{
|
|
||||||
concat(num);
|
concat(num);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
String & operator += (const __FlashStringHelper *str)
|
String & operator += (const __FlashStringHelper *str){
|
||||||
{
|
|
||||||
concat(str);
|
concat(str);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
@ -184,27 +171,22 @@ public:
|
|||||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||||
|
|
||||||
// comparison (only works w/ Strings and "strings")
|
// comparison (only works w/ Strings and "strings")
|
||||||
operator StringIfHelperType() const
|
operator StringIfHelperType() const {
|
||||||
{
|
return buffer() ? &String::StringIfHelper : 0;
|
||||||
return buffer ? &String::StringIfHelper : 0;
|
|
||||||
}
|
}
|
||||||
int compareTo(const String &s) const;
|
int compareTo(const String &s) const;
|
||||||
unsigned char equals(const String &s) const;
|
unsigned char equals(const String &s) const;
|
||||||
unsigned char equals(const char *cstr) const;
|
unsigned char equals(const char *cstr) const;
|
||||||
unsigned char operator ==(const String &rhs) const
|
unsigned char operator ==(const String &rhs) const {
|
||||||
{
|
|
||||||
return equals(rhs);
|
return equals(rhs);
|
||||||
}
|
}
|
||||||
unsigned char operator ==(const char *cstr) const
|
unsigned char operator ==(const char *cstr) const {
|
||||||
{
|
|
||||||
return equals(cstr);
|
return equals(cstr);
|
||||||
}
|
}
|
||||||
unsigned char operator !=(const String &rhs) const
|
unsigned char operator !=(const String &rhs) const {
|
||||||
{
|
|
||||||
return !equals(rhs);
|
return !equals(rhs);
|
||||||
}
|
}
|
||||||
unsigned char operator !=(const char *cstr) const
|
unsigned char operator !=(const char *cstr) const {
|
||||||
{
|
|
||||||
return !equals(cstr);
|
return !equals(cstr);
|
||||||
}
|
}
|
||||||
unsigned char operator <(const String &rhs) const;
|
unsigned char operator <(const String &rhs) const;
|
||||||
@ -223,14 +205,14 @@ public:
|
|||||||
char operator [](unsigned int index) const;
|
char operator [](unsigned int index) const;
|
||||||
char& operator [](unsigned int index);
|
char& operator [](unsigned int index);
|
||||||
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const;
|
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const;
|
||||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const
|
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const {
|
||||||
{
|
|
||||||
getBytes((unsigned char *) buf, bufsize, index);
|
getBytes((unsigned char *) buf, bufsize, index);
|
||||||
}
|
}
|
||||||
const char * c_str() const
|
const char* c_str() const { return buffer(); }
|
||||||
{
|
char* begin() { return wbuffer(); }
|
||||||
return buffer;
|
char* end() { return wbuffer() + length(); }
|
||||||
}
|
const char* begin() const { return c_str(); }
|
||||||
|
const char* end() const { return c_str() + length(); }
|
||||||
|
|
||||||
// search
|
// search
|
||||||
int indexOf(char ch) const;
|
int indexOf(char ch) const;
|
||||||
@ -241,9 +223,8 @@ public:
|
|||||||
int lastIndexOf(char ch, unsigned int fromIndex) const;
|
int lastIndexOf(char ch, unsigned int fromIndex) const;
|
||||||
int lastIndexOf(const String &str) const;
|
int lastIndexOf(const String &str) const;
|
||||||
int lastIndexOf(const String &str, unsigned int fromIndex) const;
|
int lastIndexOf(const String &str, unsigned int fromIndex) const;
|
||||||
String substring(unsigned int beginIndex) const
|
String substring(unsigned int beginIndex) const {
|
||||||
{
|
return substring(beginIndex, len());
|
||||||
return substring(beginIndex, len);
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
String substring(unsigned int beginIndex, unsigned int endIndex) const;
|
String substring(unsigned int beginIndex, unsigned int endIndex) const;
|
||||||
@ -263,9 +244,34 @@ public:
|
|||||||
double toDouble(void) const;
|
double toDouble(void) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char *buffer; // the actual char array
|
// Contains the string info when we're not in SSO mode
|
||||||
unsigned int capacity; // the array length minus one (for the '\0')
|
struct _ptr {
|
||||||
unsigned int len; // the String length (not counting the '\0')
|
char * buff;
|
||||||
|
uint16_t cap;
|
||||||
|
uint16_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
// SSO is handled by checking the last byte of sso_buff.
|
||||||
|
// When not in SSO mode, that byte is set to 0xff, while when in SSO mode it is always 0x00 (so it can serve as the string terminator as well as a flag)
|
||||||
|
// This allows strings up up to 12 (11 + \0 termination) without any extra space.
|
||||||
|
enum { SSOSIZE = sizeof(struct _ptr) + 4 }; // Characters to allocate space for SSO, must be 12 or more
|
||||||
|
enum { CAPACITY_MAX = 65535 }; // If size of capacity changed, be sure to update this enum
|
||||||
|
union {
|
||||||
|
struct _ptr ptr;
|
||||||
|
char sso_buf[SSOSIZE];
|
||||||
|
};
|
||||||
|
// Accessor functions
|
||||||
|
inline bool sso() const { return sso_buf[SSOSIZE - 1] == 0; }
|
||||||
|
inline unsigned int len() const { return sso() ? strlen(sso_buf) : ptr.len; }
|
||||||
|
inline unsigned int capacity() const { return sso() ? SSOSIZE - 1 : ptr.cap; }
|
||||||
|
inline void setSSO(bool sso) { sso_buf[SSOSIZE - 1] = sso ? 0x00 : 0xff; }
|
||||||
|
inline void setLen(int len) { if (!sso()) ptr.len = len; }
|
||||||
|
inline void setCapacity(int cap) { if (!sso()) ptr.cap = cap; }
|
||||||
|
inline void setBuffer(char *buff) { if (!sso()) ptr.buff = buff; }
|
||||||
|
// Buffer accessor functions
|
||||||
|
inline const char *buffer() const { return (const char *)(sso() ? sso_buf : ptr.buff); }
|
||||||
|
inline char *wbuffer() const { return sso() ? const_cast<char *>(sso_buf) : ptr.buff; } // Writable version of buffer
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void init(void);
|
void init(void);
|
||||||
void invalidate(void);
|
void invalidate(void);
|
||||||
@ -280,50 +286,41 @@ protected:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class StringSumHelper: public String
|
class StringSumHelper: public String {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
StringSumHelper(const String &s) :
|
StringSumHelper(const String &s) :
|
||||||
String(s)
|
String(s) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(const char *p) :
|
StringSumHelper(const char *p) :
|
||||||
String(p)
|
String(p) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(char c) :
|
StringSumHelper(char c) :
|
||||||
String(c)
|
String(c) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(unsigned char num) :
|
StringSumHelper(unsigned char num) :
|
||||||
String(num)
|
String(num) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(int num) :
|
StringSumHelper(int num) :
|
||||||
String(num)
|
String(num) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(unsigned int num) :
|
StringSumHelper(unsigned int num) :
|
||||||
String(num)
|
String(num) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(long num) :
|
StringSumHelper(long num) :
|
||||||
String(num)
|
String(num) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(unsigned long num) :
|
StringSumHelper(unsigned long num) :
|
||||||
String(num)
|
String(num) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(float num) :
|
StringSumHelper(float num) :
|
||||||
String(num)
|
String(num) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
StringSumHelper(double num) :
|
StringSumHelper(double num) :
|
||||||
String(num)
|
String(num) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const String emptyString;
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
#endif // String_class_h
|
#endif // String_class_h
|
||||||
|
Loading…
Reference in New Issue
Block a user