Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

WString - assume c-string is a pointer to flash in all cases#9272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
mcspr wants to merge19 commits intoesp8266:master
base:master
Choose a base branch
Loading
frommcspr:string/cstr-pgmspace-funcs
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
19 commits
Select commitHold shift + click to select a range
86a9ece
wip
mcsprAug 27, 2025
78f2ba3
drop arduino legacy buffer assumptions & enforce length checks instead
mcsprAug 29, 2025
4ad1080
size_t -> unsigned int to simplify host build typing
mcsprAug 29, 2025
acb9b49
fixup extern operator+ dependency on insert
mcsprAug 29, 2025
a8532ba
operator< & operator> differences
mcsprAug 29, 2025
98ac268
typo
mcsprAug 29, 2025
cbd6ab2
fixup set lookup output on failure
mcsprAug 29, 2025
3f60138
branches for different str locations
mcsprSep 10, 2025
1b3b3f8
note about strlen in replace
mcsprSep 10, 2025
6d28d99
consistent null checks
mcsprSep 10, 2025
edb2230
update replacement test
mcsprSep 10, 2025
d39fefb
explicit strstr & strstr_P overload selection
mcsprSep 10, 2025
d1adaef
allow to use gdb as well as pass args to catch
mcsprOct 27, 2025
3da6ae7
missing reference tests for operator lt gt etc
mcsprOct 27, 2025
6a22369
fixup string.h missing memmem & pgm reading float / double
mcsprOct 27, 2025
48f9fef
prefer mem* funcs instead of str*
mcsprOct 27, 2025
50956de
missing file
mcsprOct 28, 2025
70222c2
fixup replace() for diff>0
mcsprOct 28, 2025
4dd4ae5
fixup lastIndexOfImpl checking ptr instead of offset
mcsprOct 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
577 changes: 380 additions & 197 deletionscores/esp8266/WString.cpp
View file
Open in desktop

Large diffs are not rendered by default.

164 changes: 132 additions & 32 deletionscores/esp8266/WString.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,9 +54,11 @@ class String {
String() __attribute__((always_inline)) { // See init()
init();
}
String(const char *cstr);
String(const String &str);
String(const __FlashStringHelper *str);
String(const char *cstr);
String(const __FlashStringHelper *str) :
String(reinterpret_cast<const char *>(str))
{}
String(String &&rval) noexcept;

explicit String(char c) {
Expand DownExpand Up@@ -134,7 +136,9 @@ class String {
String &operator =(const String &rhs);
String &operator =(String &&rval) noexcept;
String &operator =(const char *cstr);
String &operator =(const __FlashStringHelper *str);
String &operator =(const __FlashStringHelper *str) {
return *this = reinterpret_cast<const char *>(str);
}
String &operator =(char c);

String &operator =(unsigned char value) {
Expand DownExpand Up@@ -189,8 +193,10 @@ class String {
// concatenation is considered unsuccessful.
bool concat(const String &str);
bool concat(const char *cstr);
bool concat(const char *cstr, unsigned int length);
bool concat(const __FlashStringHelper *str);
bool concat(const char *str, unsigned int length);
bool concat(const __FlashStringHelper *str) {
return concat(reinterpret_cast<const char *>(str));
}
bool concat(char c);

bool concat(unsigned char c);
Expand DownExpand Up@@ -218,36 +224,87 @@ class String {
}

int compareTo(const String &s) const;
int compareTo(const char *cstr) const;
int compareTo(const char *str, unsigned int length) const;
int compareTo(const __FlashStringHelper *str) const {
return compareTo(reinterpret_cast<const char *>(str));
}

bool equals(const String &s) const;
bool equals(const char *cstr) const;
bool equals(const __FlashStringHelper *s) const;
bool equals(const char *str, unsigned int length) const;
bool equals(const __FlashStringHelper *str) const {
return equals(reinterpret_cast<const char *>(str));
}

bool operator ==(const String &rhs) const {
return equals(rhs);
}
bool operator ==(const char *cstr) const {
return equals(cstr);
}
bool operator ==(const __FlashStringHelper *str) const {
return equals(str);
}
bool operator !=(const String &rhs) const {
return !equals(rhs);
}
bool operator !=(const char *cstr) const {
return !equals(cstr);
}
bool operator !=(const __FlashStringHelper *str) const {
return equals(str);
}
bool operator <(const String &rhs) const;
bool operator <(const char *rhs) const;
bool operator <(const __FlashStringHelper *rhs) const {
return *this < reinterpret_cast<const char *>(rhs);
}
bool operator >(const String &rhs) const;
bool operator >(const char *rhs) const;
bool operator >(const __FlashStringHelper *rhs) const {
return *this > reinterpret_cast<const char *>(rhs);
}
bool operator <=(const String &rhs) const;
bool operator <=(const char *rhs) const;
bool operator <=(const __FlashStringHelper *rhs) const {
return *this <= reinterpret_cast<const char *>(rhs);
}
bool operator >=(const String &rhs) const;
bool operator >=(const char *rhs) const;
bool operator >=(const __FlashStringHelper *rhs) const {
return *this >= reinterpret_cast<const char *>(rhs);
}

bool equalsIgnoreCase(const String &s) const;
bool equalsIgnoreCase(const __FlashStringHelper *s) const;
bool equalsIgnoreCase(const char *s) const;
bool equalsIgnoreCase(const char *str, unsigned int length) const;
bool equalsIgnoreCase(const __FlashStringHelper *s) const {
return equalsIgnoreCase(reinterpret_cast<const char *>(s));
}

unsigned char equalsConstantTime(const String &s) const;
unsigned char equalsConstantTime(const char *str, unsigned int length) const;

bool startsWith(const String &prefix) const;
bool startsWith(const char *prefix) const;
bool startsWith(const __FlashStringHelper *prefix) const;
bool startsWith(const __FlashStringHelper *prefix) const {
return startsWith(reinterpret_cast<const char *>(prefix));
}

bool startsWith(const String &prefix, unsigned int offset) const;
bool startsWith(const __FlashStringHelper *prefix, unsigned int offset) const;
bool startsWith(const char *prefix, unsigned int offset) const;
bool startsWith(const char *str, unsigned int length, unsigned int offset) const;
bool startsWith(const __FlashStringHelper *prefix, unsigned int offset) const {
return startsWith(reinterpret_cast<const char *>(prefix), offset);
}

bool endsWith(const String &suffix) const;
bool endsWith(const char *suffix) const;
bool endsWith(const __FlashStringHelper *suffix) const;
bool endsWith(const char *str, unsigned int length) const;
bool endsWith(const __FlashStringHelper *suffix) const {
return endsWith(reinterpret_cast<const char *>(suffix));
}

// character access
char charAt(unsigned int index) const {
Expand All@@ -256,10 +313,10 @@ class String {
void setCharAt(unsigned int index, char c);
char operator [](unsigned int index) const;
char &operator [](unsigned int index);
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 {
getBytes((unsigned char *) buf, bufsize, index);
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const {
toCharArray((char *)buf, bufsize, index);
}
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const;
const char *c_str() const { return buffer(); }
char *begin() { return wbuffer(); }
char *end() { return wbuffer() + length(); }
Expand All@@ -270,15 +327,23 @@ class String {
int indexOf(char ch, unsigned int fromIndex = 0) const;
int indexOf(const char *str, unsigned int fromIndex = 0) const;
int indexOf(const __FlashStringHelper *str, unsigned int fromIndex = 0) const {
return indexOf((const char*)str, fromIndex);
return indexOf(reinterpret_cast<const char*>(str), fromIndex);
}
int indexOf(const String &str, unsigned int fromIndex = 0) const;
int lastIndexOf(char ch) const;
int lastIndexOf(char ch, unsigned int fromIndex) const;
int lastIndexOf(const String &str) const;
int lastIndexOf(const String &str, unsigned int fromIndex) const;
int lastIndexOf(const __FlashStringHelper *str) const;
int lastIndexOf(const __FlashStringHelper *str, unsigned int fromIndex) const;
int lastIndexOf(const char *cstr) const;
int lastIndexOf(const char *cstr, unsigned int fromIndex) const;
int lastIndexOf(const char *str, unsigned int length, unsigned int fromIndex) const;

int lastIndexOf(const __FlashStringHelper *str) const {
return lastIndexOf(reinterpret_cast<const char *>(str));
}
int lastIndexOf(const __FlashStringHelper *str, unsigned int fromIndex) const {
return lastIndexOf(reinterpret_cast<const char *>(str), fromIndex);
}
String substring(unsigned int beginIndex) const {
return substring(beginIndex, len());
}
Expand All@@ -287,11 +352,24 @@ class String {
// modification
void replace(char find, char replace);
void replace(const String &find, const String &replace);
void replace(const String &find, const char *replace);
void replace(const String &find, const __FlashStringHelper *replace) {
this->replace(find, reinterpret_cast<const char *>(replace));
}
void replace(const char *find, const String &replace);
void replace(const __FlashStringHelper *find, const String &replace);
void replace(const __FlashStringHelper *find, const String &replace) {
this->replace(reinterpret_cast<const char *>(find), replace);
}
void replace(const char *find, const char *replace);
void replace(const __FlashStringHelper *find, const char *replace);
void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace);
void replace(const char *find, const __FlashStringHelper *replace) {
this->replace(find, reinterpret_cast<const char *>(replace));
}
void replace(const __FlashStringHelper *find, const char *replace) {
this->replace(reinterpret_cast<const char *>(find), replace);
}
void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) {
this->replace(reinterpret_cast<const char *>(find), reinterpret_cast<const char *>(replace));
}

// Pass the biggest integer if the count is not specified.
// The remove method below will take care of truncating it at the end of the string.
Expand DownExpand Up@@ -350,7 +428,6 @@ class String {
friend String operator +(const char *lhs, String &&rhs);
friend String operator +(const __FlashStringHelper *lhs, String &&rhs);

protected:
// TODO: replace init() with a union constructor, so it's called implicitly

void init(void) __attribute__((always_inline)) {
Expand All@@ -376,17 +453,43 @@ class String {
bool changeBuffer(unsigned int maxStrLen);

// copy or insert at a specific position
String &copy(const char *cstr, unsigned int length);
String &copy(const __FlashStringHelper *pstr, unsigned int length);
String &copy(const char *str, unsigned int length);
String &copy(const __FlashStringHelper *str, unsigned int length) {
return copy(reinterpret_cast<const char *>(str), length);
}

void replace(const char *find, unsigned int find_len, const char *replace, unsigned int replace_len);

String &insert(size_t position, char);
String &insert(size_t position, const char *);
String &insert(size_t position, const __FlashStringHelper *);
String &insert(size_t position, const char *, size_t length);
String &insert(size_t position, const String &);
String &insert(size_t position, const char * str);
String &insert(size_t position, const __FlashStringHelper *str) {
return insert(position, reinterpret_cast<const char *>(str));
}
String &insert(size_t position, const char * str, unsigned int length);
String &insert(size_t position, const String &str);

// rvalue helper
void move(String &rhs) noexcept;

// internal implementations rely on func wrappers
using internal_memcmp_t = int (*)(const void *, const void *, size_t);

int compareToImpl(internal_memcmp_t, const char *str, unsigned int length) const;
bool equalsImpl(internal_memcmp_t, const char *str, unsigned int length) const;
bool startsWithImpl(internal_memcmp_t, const char *str, unsigned int length, unsigned int offset) const;
bool endsWithImpl(internal_memcmp_t, const char *str, unsigned int length) const;

using internal_memcasecmp_t = int (*)(const void *, const void *, size_t);

bool equalsIgnoreCaseImpl(internal_memcasecmp_t, const char *str, unsigned int length) const;

using internal_memmem_t = void *(*)(const void *, size_t, const void *, size_t);

int indexOfImpl(internal_memmem_t, const char *str, unsigned int length, unsigned int fromIndex) const;
int lastIndexOfImpl(internal_memmem_t, const char *str, unsigned int length, unsigned int fromIndex) const;
void replaceImpl(internal_memmem_t impl, const char *find, unsigned int find_len, const char *replace, unsigned int replace_len);

friend struct __StringImpl;
};

// concatenation (note that it's done using non-method operators to handle both possible type refs)
Expand DownExpand Up@@ -432,10 +535,7 @@ inline String operator +(char lhs, String &&rhs) {
return std::move(rhs.insert(0, lhs));
}

// both `char*` and `__FlashStringHelper*` are implicitly converted into `String()`, calling the `operator+(const String& ...);`
// however, here we:
// - do an automatic `reserve(total length)` for the resulting string
// - possibly do rhs.insert(0, ...), when &&rhs capacity could fit both
// Similarly, allow c-strings and `F(...)` as both lhs and rhs

String operator +(const char *lhs, const String &rhs);

Expand All@@ -444,11 +544,11 @@ inline String operator +(const char *lhs, String &&rhs) {
}

inline String operator +(const __FlashStringHelper *lhs, const String &rhs) {
return reinterpret_cast<const char*>(lhs) + rhs;
return reinterpret_cast<const char*>(lhs) + rhs;
}

inline String operator +(const __FlashStringHelper *lhs, String &&rhs) {
return std::move(rhs.insert(0, lhs));
returnreinterpret_cast<const char *>(lhs) +std::move(rhs);
}

extern const String emptyString;
Expand Down
3 changes: 2 additions & 1 deletiontests/host/Makefile
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -194,6 +194,7 @@ INC_PATHS += \
../../tools/sdk/lwip2/include \
)

TEST_WRAPPER ?=
TEST_ARGS ?=

TEST_CPP_FILES := \
Expand DownExpand Up@@ -258,7 +259,7 @@ CI:# run CI
doCI: build-info $(OUTPUT_BINARY) valgrind test gcov

test: $(OUTPUT_BINARY)# run host test for CI
$(OUTPUT_BINARY) $(TEST_ARGS)
$(TEST_WRAPPER) $(OUTPUT_BINARY) $(TEST_ARGS)

.PHONY: clean
clean: clean-lcov clean-objects
Expand Down
3 changes: 3 additions & 0 deletionstests/host/common/stdio.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
#pragma once
#include_next <stdio.h>
#include <sys/stdio.h>
3 changes: 3 additions & 0 deletionstests/host/common/string.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
#pragma once
#include_next <string.h>
#include <sys/string.h>
54 changes: 42 additions & 12 deletionstests/host/core/test_string.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,12 +44,34 @@ TEST_CASE("String::trim", "[core][String]")

TEST_CASE("String::replace", "[core][String]")
{
String str;
str = "The quick brown fox jumped over the lazy dog.";
String find = "fox";
String replace = "vulpes vulpes";
str.replace(find, replace);
const char data[] = "The quick brown fox jumped over the lazy dog.";
String str = data;
str.replace("fox", "vulpes vulpes");
REQUIRE(str == "The quick brown vulpes vulpes jumped over the lazy dog.");
str.replace("vulpes", "lis lis");
REQUIRE(str == "The quick brown lis lis lis lis jumped over the lazy dog.");
str.replace("lazy dog.", "canis piger");
REQUIRE(str == "The quick brown lis lis lis lis jumped over the canis piger");
str.replace("brown lis lis", "lis");
REQUIRE(str == "The quick lis lis lis jumped over the canis piger");
str.replace("lis", "fox");
REQUIRE(str == "The quick fox fox fox jumped over the canis piger");
str.replace("fox fox", "kot");
REQUIRE(str == "The quick kot fox jumped over the canis piger");
str.replace("fox jumped", "red felis");
REQUIRE(str == "The quick kot red felis over the canis piger");
str.replace(" over ", " jumped over ");
REQUIRE(str == "The quick kot red felis jumped over the canis piger");
str.replace("canis piger", "lazy dog");
REQUIRE(str == "The quick kot red felis jumped over the lazy dog");
str.replace("dog", "dog.");
REQUIRE(str == "The quick kot red felis jumped over the lazy dog.");
str.replace(" kot", "");
REQUIRE(str == "The quick red felis jumped over the lazy dog.");
str.replace("red", "brown");
REQUIRE(str == "The quick brown felis jumped over the lazy dog.");
str.replace("felis", "fox");
REQUIRE(str == data);
}

TEST_CASE("String(value, base)", "[core][String]")
Expand DownExpand Up@@ -186,12 +208,19 @@ TEST_CASE("String concantenation", "[core][String]")

TEST_CASE("String comparison", "[core][String]")
{
String alpha("I like fish!");
REQUIRE(String("a") < String("b")); // compareTo() reference comparisons
REQUIRE(String("1") < String("2"));
REQUIRE(String("999") > String("1000"));
String alpha("I like fish!"); // compareTo()
REQUIRE(alpha < "I like tacos!");
REQUIRE(alpha > "I like bacon!");
REQUIRE(alpha > "I like cod!");
REQUIRE(alpha >= "I like beef!");
REQUIRE(alpha <= "I like soup!");
REQUIRE(alpha.equalsIgnoreCase("i LiKe FiSh!"));
REQUIRE(!alpha.equalsIgnoreCase("i LiKe FiSh! And ChIPs!"));
REQUIRE(alpha.equalsConstantTime("I like fish!"));
REQUIRE(alpha != "I like fish?");
REQUIRE(alpha != "I like fish?"); // equals()
REQUIRE(alpha.startsWith("I like"));
REQUIRE(!alpha.startsWith("I lick"));
REQUIRE(alpha.startsWith("fish", 7));
Expand DownExpand Up@@ -581,11 +610,11 @@ TEST_CASE("String chaining", "[core][String]")

// make sure we can chain a combination of things to form a String
REQUIRE((String(chunks[0]) + String(chunks[1]) + String(chunks[2]) + String(chunks[3])) == all);
REQUIRE((chunks[0] + String(chunks[1]) +F(chunks[2]) + chunks[3]) == all);
REQUIRE((String(chunks[0]) +F(chunks[1]) +F(chunks[2]) + String(chunks[3])) == all);
REQUIRE(('~' + String(&chunks[0][0] + 1) + chunks[1] + String(chunks[2]) +F(chunks[3]))
REQUIRE((chunks[0] + String(chunks[1]) +FPSTR(chunks[2]) + chunks[3]) == all);
REQUIRE((String(chunks[0]) +FPSTR(chunks[1]) +FPSTR(chunks[2]) + String(chunks[3])) == all);
REQUIRE(('~' + String(&chunks[0][0] + 1) + chunks[1] + String(chunks[2]) +FPSTR(chunks[3]))
== all);
REQUIRE((String(chunks[0]) + '6' + (&chunks[1][0] + 1) + String(chunks[2]) +F(chunks[3]))
REQUIRE((String(chunks[0]) + '6' + (&chunks[1][0] + 1) + String(chunks[2]) +FPSTR(chunks[3]))
== all);

// these are still invalid (and also cannot compile at all):
Expand All@@ -600,7 +629,8 @@ TEST_CASE("String chaining", "[core][String]")
String tmp(chunks[3]);
tmp.reserve(2 * all.length());
auto* ptr = tmp.c_str();
String result("~1" + String(&chunks[0][0] + 2) + F(chunks[1]) + chunks[2] + std::move(tmp));
String result("~1" + String(&chunks[0][0] + 2) + FPSTR(chunks[1]) + chunks[2]
+ std::move(tmp));
REQUIRE(result == all);
REQUIRE(static_cast<const void*>(result.c_str()) == static_cast<const void*>(ptr));
}
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp