Maps
Introduction
A FSTR::Map
is analogous to the Wiring HashMap
class, allowing content to be indexed using
a key value.
The Map contains an array of FSTR::MapPair
structures:
struct MapPair<KeyType, ContentType> {
KeyType key_;
ContentType* content_;
};
KeyType
can be any simple type such as char
, int
, float
, enum
etc.
It may also be a String
Object (or, more precisely, String*
).
ContentType
can be any Object type (String, Array, Vector or Map).
This allows hierarchical structures to be created.
Example: int ⇒ String
Here’s a basic example using integer keys:
#include <FlashString/Map.hpp>
IMPORT_FSTR_LOCAL(content1, PROJECT_DIR "/files/index.html");
IMPORT_FSTR_LOCAL(content2, PROJECT_DIR "/files/favicon.html");
DEFINE_FSTR_MAP(intmap, int, FSTR::String,
{35, &content1},
{180, &content2}
);
You should generally use IMPORT_FSTR_LOCAL()
when referencing imported objects.
If you need global access to imported data as well, then use IMPORT_FSTR()
.
We can now do this:
void printValue(int key)
{
auto value = intmap[key];
if(value) {
Serial << "Found '" << value.key() << "' in map, containing " << value.content.length() << " chars" << endl;
Serial << value << endl;
} else {
Serial << "Couldn't find '" << key << "' in map" << endl;
}
}
Example: String ⇒ String
Both the key and the content are stored as Strings:
#include <FlashString/Map.hpp>
DEFINE_FSTR_LOCAL(key1, "index.html");
DEFINE_FSTR_LOCAL(key2, "favicon.ico");
IMPORT_FSTR_LOCAL(content1, PROJECT_DIR "/files/index.html");
IMPORT_FSTR_LOCAL(content2, PROJECT_DIR "/files/favicon.html");
DEFINE_FSTR_MAP(fileMap, FlashString, FlashString,
{&key1, &content1},
{&key2, &content2},
);
We can now do this:
void onFile(HttpRequest& request, HttpResponse& response)
{
String fileName = request.uri.getRelativePath();
auto& value = fileMap[fileName];
if(value) {
// Found
Serial << "Found '" << value.key() << "' in fileMap" << endl;
auto stream = new FlashMemoryStream(value);
response.sendDataStream(stream, ContentType::fromFullFileName(fileName));
} else {
Serial << "File '" << fileName << "' not found" << endl;
}
}
Note
As with Vector<String>
, Map<String, ...>
lookups are by default case-insensitive.
If you require a case-sensitive lookup, use the indexOf
method with ignoreCase = false
.
Structure
The macro in the first example above produces a structure like this:
constexpr const struct {
Map<MapPair<int, String>> object;
MapPair<int, String> data[2];
} __fstr__intmap PROGMEM = {
{16},
{35, &content1},
{180, &content2},
};
const Map<int, String>& intmap PROGMEM = __fstr__intmap.object;
Note: FSTR::
namespace qualifier omitted for clarity.
Usually, each MapPair is 8 bytes, but if the key is a double or int64 it would be 12 bytes.
Macros
-
DECLARE_FSTR_MAP(name, KeyType, ContentType)
Declare a global Map& reference.
Note
Use DEFINE_FSTR_MAP to instantiate the global object
- Parameters:
name – Name of the Map& reference to define
KeyType – Integral type to use for key
ContentType – Object type to declare for content
-
DEFINE_FSTR_MAP(name, KeyType, ContentType, ...)
Define a Map Object with global reference.
Note
Size will be calculated
- Parameters:
name – Name of the Map& reference to define
KeyType – Integral type to use for key
ContentType – Object type to declare for content
... – List of MapPair definitions { key, &content }
-
DEFINE_FSTR_MAP_LOCAL(name, KeyType, ContentType, ...)
Like DEFINE_FSTR_MAP except reference is declared static constexpr.
-
DEFINE_FSTR_MAP_SIZED(name, KeyType, ContentType, size, ...)
Define a Map Object with global reference, specifying the number of elements.
- Parameters:
name – Name of the Map& reference to define
KeyType – Integral type to use for key
ContentType – Object type to declare for content
size – Number of elements
... – List of MapPair definitions { key, &content }
-
DEFINE_FSTR_MAP_SIZED_LOCAL(name, KeyType, ContentType, size, ...)
Like DEFINE_FSTR_MAP_SIZED except reference is declared static.
-
DEFINE_FSTR_MAP_DATA(name, KeyType, ContentType, ...)
Define a Map data structure.
Note
Size will be calculated
- Parameters:
name – Name of data structure
KeyType – Integral type to use for key
ContentType – Object type to declare for content
... – List of MapPair definitions { key, &content }
-
DEFINE_FSTR_MAP_DATA_SIZED(name, KeyType, ContentType, size, ...)
Define a Map data structure, specifying the number of elements.
- Parameters:
name – Name of data structure
KeyType – Integral type to use for key
ContentType – Object type to declare for content
size – Number of elements
... – List of MapPair definitions { key, &content }
Class Templates
-
template<typename KeyType, class ContentType, class Pair = MapPair<KeyType, ContentType>>
class Map : public FSTR::Object<Map<KeyType, ContentType>, MapPair<KeyType, ContentType>> Class template to access an associative map.
- Template Parameters:
KeyType –
ContentType –
Public Functions
- inline FSTR_ALIGN32 const Pair valueAt (unsigned index) const
Get a map entry by index, if it exists.
Note
Result validity can be checked using if()
- template<typename TRefKey, typename T = KeyType> inline FSTR_ALIGN32 std::enable_if<!std::is_class< T >::value, int >::type indexOf (const TRefKey &key) const
Lookup an integral key and return the index.
- Parameters:
key – Key to locate, must be compatible with KeyType for equality comparison
- Return values:
int – If key isn’t found, return -1
- template<typename TRefKey, typename T = KeyType> inline FSTR_ALIGN32 std::enable_if< std::is_same< T, String >::value, int >::type indexOf (const TRefKey &key, bool ignoreCase=true) const
Lookup a String key and return the index.
- Parameters:
key –
ignoreCase – Whether search is case-sensitive (default: true)
- Return values:
int – If key isn’t found, return -1
-
template<typename KeyType, class ContentType>
class MapPair describes a pair mapping key => data for a specified key type
- Template Parameters:
Public Functions
-
inline operator IfHelperType() const
Provides bool() operator to determine if Pair is valid.
- template<typename T = KeyType> inline FSTR_ALIGN32 std::enable_if<!std::is_class< T >::value, KeyType >::type key () const
Get the key (non-class key types)
- template<typename T = KeyType> inline FSTR_ALIGN32 std::enable_if< std::is_same< T, String >::value, const KeyType & >::type key () const
Get the key (String key type)
-
inline const ContentType &content() const
Accessor to get a reference to the content.