diff --git a/map.rst b/map.rst index df4fb6c..c3a1a76 100644 --- a/map.rst +++ b/map.rst @@ -102,14 +102,14 @@ Structure The macro in the first example above produces a structure like this:: constexpr const struct { - ObjectBase object; + Map> object; MapPair data[2]; } __fstr__intmap PROGMEM = { {16}, {35, &content1}, {180, &content2}, }; - const Map& intmap = __fstr__intmap.object.as>(); + const Map& intmap PROGMEM = __fstr__intmap.object; Note: ``FSTR::`` namespace qualifier omitted for clarity. diff --git a/object.rst b/object.rst index 5c728cc..7dfb39e 100644 --- a/object.rst +++ b/object.rst @@ -59,30 +59,35 @@ base class, and looks like this (methods omitted):: ``flashLength_`` must not be accessed directly; use the ``length()`` method instead. -Data structures are created like this:: +Data structures are created using, for example, ``DEFINE_FSTR(helloData, "hello")``. +This generates the following layout:: constexpr const struct { - ObjectBase object; + FSTR::String object; char data[8]; - } flashHelloData PROGMEM = { + } __fstr__helloData PROGMEM = { {5}, "hello" }; + const FSTR::String& helloData PROGMEM = __fstr__helloData.object; -The ``object`` field may then be cast to a reference of the required type, like this:: +.. note:: - auto& str = flashHelloData.object.as(); + The ``__fstr__`` prefix ensures that these structures are stored in flash memory on the esp8266. + When templates are involved the ``PROGMEM`` segment attribute gets discarded. -If you want to access it as an array, do this:: - - auto& arr = str.as>(); + Do not access ``__fstr__helloData`` directly, it may change in future library versions. References are an efficient and convenient way to access an Object, and should not consume -any memory themselves as the compiler/linker resolve them to the actual object. +any memory themselves as the compiler/linker resolves them to the actual object. However, in practice the Espressif compiler stores a full pointer to most things to support relative addressing, and if the references aren't declared PROGMEM they'll consume RAM. +Objects may be cast to a reference of another required type, like this:: + + auto& arr = helloData.as>(); + Copy behaviour -------------- @@ -105,16 +110,7 @@ This means classes cannot have: - virtual functions - base classes (until C++17) -This is why :cpp:class:`FSTR::ObjectBase` is used to define data structures. - -Classes created using the :cpp:class:`FSTR::Object` template ensures the necessary constructors -are available to do this:: - - auto myCopy = flashHelloData.object.as(); - Serial.print("myCopy.length() = "); - Serial.println(myCopy.length()); - -The macros create an appropriate Object& reference for you. +This is why objects have no constructors or assignment operators. Structure checks @@ -129,12 +125,10 @@ You may encounter one of the following errors during compilation: - FSTR structure not POD This generally means one or more of the arguments in the initialisation data is not ``constexpr``. -Most compilers are quite relaxed about this but ``GCC 4.8.5`` is particularly thick. In testing, this happens with references for global Objects, which of course cannot be constexpr. -To fix it, the offending Object either needs to be redefined LOCAL, or if the Object data is in -scope (i.e. defined in the same source file) then you can get a direct pointer to it using -the :c:func:`FSTR_PTR` macro. +To fix it, the offending Object needs to be redefined LOCAL. + Macros ------ diff --git a/src/include/FlashString/Object.hpp b/src/include/FlashString/Object.hpp index 5f6cfb0..d52725d 100644 --- a/src/include/FlashString/Object.hpp +++ b/src/include/FlashString/Object.hpp @@ -57,28 +57,9 @@ /** * @brief Given an Object& reference, return a pointer to the actual object * @param objref - * - * When an Object pointer is required, such when defining entries for a Vector or Map, - * it is usually sufficient to use &objref. - * - * However, some older compilers such as GCC 4.8.5 requires such references to - * be declared constexpr. For example, this fails with `FSTR structure not POD`: - * - * DEFINE_FSTR(globalStringRef, "This creates a global reference"); - * DEFINE_VECTOR(myVector, FSTR::String, &globalStringRef); - * ^^^ - * - * Global references cannot be declared constexpr, so changing DEFINE_FSTR to DEFINE_FSTR_LOCAL - * will fix the problem. - * - * Another solution is to get a direct pointer to the actual data structure: - * - * DEFINE_VECTOR(myVector, FSTR::String, FSTR_PTR(globalStringRef)); - * - * We can only do this of course if the data structure is in scope. - * + * @note This macro was provided for use with old compilers (e.g. GCC 4.8.5) but is no longer required. */ -#define FSTR_PTR(objref) (&FSTR_DATA_NAME(objref).object) +#define FSTR_PTR(objref) (&objref) /** * @brief Check structure is POD-compliant and correctly aligned diff --git a/string.rst b/string.rst index 2436e78..64a59a2 100644 --- a/string.rst +++ b/string.rst @@ -91,7 +91,7 @@ This is equivalent to:: Nested Inline Strings --------------------- -It would be really useful to be able to use inline Strings this within nested structures, +It would be really useful to be able to use inline Strings within nested structures, and this can be done **provided those structures are in RAM**. .. important:: Inline Strings cannot be used when defining Vectors or Maps. @@ -99,7 +99,7 @@ and this can be done **provided those structures are in RAM**. Here's is a simplified structure we will attempt to initialize:: static const struct { - FlashString* string; + const FlashString* string; } flashData PROGMEM = { FS_PTR("Inline Flash String") }; Serial.println(*flashData.string); diff --git a/test/app/custom.cpp b/test/app/custom.cpp index 3868639..5c2b274 100644 --- a/test/app/custom.cpp +++ b/test/app/custom.cpp @@ -48,6 +48,11 @@ class CustomTest : public TestGroup REQUIRE(customObject.description() == F("Object Description ")); REQUIRE(customObject.content().length() == sizeof(data)); REQUIRE(memcmp_P(data, customObject.content().data(), sizeof(data)) == 0); + + static const struct { + const FlashString* string; + } flashData = {FS_PTR("Inline Flash String")}; + Serial.println(*flashData.string); } }; diff --git a/test/app/data.cpp b/test/app/data.cpp index 2249e64..e71561a 100644 --- a/test/app/data.cpp +++ b/test/app/data.cpp @@ -64,8 +64,7 @@ DEFINE_FSTR_MAP(stringMap, FSTR::String, FSTR::String, {&key1, &FS_content1}, {& DEFINE_FSTR_MAP(enumMap, MapKey, FSTR::String, {KeyA, &FS_content1}, {KeyB, &FS_content2}); -// Note the use of FSTR_PTR(), required for GCC 4.8.5 because stringVector is a global reference and therefore not constexpr -DEFINE_FSTR_MAP(vectorMap, FSTR::String, FSTR::Vector, {&key1, FSTR_PTR(stringVector)}); +DEFINE_FSTR_MAP(vectorMap, FSTR::String, FSTR::Vector, {&key1, &stringVector}); /** * Speed diff --git a/todo.rst b/todo.rst index 0bec490..8ae5340 100644 --- a/todo.rst +++ b/todo.rst @@ -14,14 +14,6 @@ Benchmark filemap - File access times - File transfer times -Implement stream operator << - For simpler printing. This is a large architectural decision as Sming doesn't have any of this, - neither it seems does Arduino although some libraries add support for it. - - The advantage over Print/Printable is that support can be added using template functions - without modifying the classes themselves. Formatting statements can be inserted to customise - the output. - Formatted print output We have separate argument for Array printing, but if we want to customise the text for each item diff --git a/upgrade.rst b/upgrade.rst index 59c9b81..094e7e1 100644 --- a/upgrade.rst +++ b/upgrade.rst @@ -16,6 +16,15 @@ This library was introduced to Sming in version 4.0.1. If you are migrating from Sming 3.7.0 or later and have used FlashString in your projects, some minor changes may be necessary. +Version 2.1 +----------- + +Support for copied strings was removed to improve portability and performance. +Code simplification allowed use of compilers other than GCC, such as Clang/LLVM. + +Code impact is minimal since FlashString objects should be passed by reference or pointer. + + FlashString ~~~~~~~~~~~ diff --git a/vector.rst b/vector.rst index d0dfe67..e0340fd 100644 --- a/vector.rst +++ b/vector.rst @@ -6,12 +6,7 @@ Vectors Introduction ------------ -A :cpp:class:`FSTR::Vector` is an array of Object pointers:: - - struct Vector { - FSTR::Object object; - ObjectType* entries[]; - }; +A :cpp:class:`FSTR::Vector` is an array of Object pointers. A key use for this is the construction of string tables. @@ -67,8 +62,8 @@ Structure The above example generates a structure like this:: - const struct { - ObjectBase object; + constexpr const struct { + Vector object; String* entries[4]; } __fstr__myTable PROGMEM = { {16}, @@ -77,7 +72,7 @@ The above example generates a structure like this:: nullptr, &str3, }; - const Vector& myTable PROGMEM = __fstr__myTable.as>(); + const Vector& myTable PROGMEM = __fstr__myTable.object; Note: ``FSTR::`` namespace qualifier omitted for clarity.