diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 8533183b..f55d6112 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -149,7 +149,7 @@ To do that, you use these methods: * `Layer(layer_name, is_area)`: write this node/way to the named layer. This is how you put objects in your vector tile. is_area (true/false) specifies whether a way should be treated as an area, or just as a linestring. * `LayerAsCentroid(layer_name, algorithm, role, role...)`: write a single centroid point for this way to the named layer (useful for labels and POIs). Only the first argument is required. `algorithm` can be "polylabel" (default) or "centroid". The third arguments onwards specify relation roles: if you're processing a multipolygon-type relation (e.g. a boundary) and it has a "label" node member, then by adding "label" as an argument here, this will be used in preference to the calculated point. * `Attribute(key,value,minzoom)`: add an attribute to the most recently written layer. Argument `minzoom` is optional, use it if you do not want to write the attribute on lower zoom levels. -* `AttributeNumeric(key,value,minzoom)`, `AttributeBoolean(key,value,minzoom)`: for numeric/boolean columns. +* `AttributeNumeric(key,value,minzoom)`, `AttributeInteger(key,value,minzoom)`, `AttributeBoolean(key,value,minzoom)`: for numeric (floating-point), integer and boolean columns. * `Id()`: get the OSM ID of the current object. * `IsClosed()`: returns true if the current object is a closed area. * `IsMultiPolygon()`: returns true if the current object is a multipolygon. diff --git a/include/attribute_store.h b/include/attribute_store.h index 75ff6e9c..d5a2d386 100644 --- a/include/attribute_store.h +++ b/include/attribute_store.h @@ -42,7 +42,7 @@ class AttributeKeyStore { std::map keys2index; }; -enum class AttributePairType: uint8_t { String = 0, Float = 1, Bool = 2 }; +enum class AttributePairType: uint8_t { String = 0, Float = 1, Bool = 2, Int = 3 }; // AttributePair is a key/value pair (with minzoom) #pragma pack(push, 1) struct AttributePair { @@ -50,32 +50,36 @@ struct AttributePair { AttributePairType valueType : 2; uint8_t minzoom : 5; // Support zooms from 0..31. In practice, we expect z16 to be the biggest minzoom. union { - float floatValue_; + double doubleValue_; PooledString stringValue_; }; AttributePair(uint32_t keyIndex, bool value, char minzoom) - : keyIndex(keyIndex), valueType(AttributePairType::Bool), minzoom(minzoom), floatValue_(value ? 1 : 0) + : keyIndex(keyIndex), valueType(AttributePairType::Bool), minzoom(minzoom), doubleValue_(value ? 1 : 0) { } AttributePair(uint32_t keyIndex, const PooledString& value, char minzoom) : keyIndex(keyIndex), valueType(AttributePairType::String), stringValue_(value), minzoom(minzoom) { } - AttributePair(uint32_t keyIndex, float value, char minzoom) - : keyIndex(keyIndex), valueType(AttributePairType::Float), minzoom(minzoom), floatValue_(value) + AttributePair(uint32_t keyIndex, double value, char minzoom) + : keyIndex(keyIndex), valueType(AttributePairType::Float), minzoom(minzoom), doubleValue_(value) + { + } + AttributePair(uint32_t keyIndex, int value, char minzoom) + : keyIndex(keyIndex), valueType(AttributePairType::Int), minzoom(minzoom), doubleValue_(static_cast(value)) { } AttributePair(const AttributePair& other): keyIndex(other.keyIndex), valueType(other.valueType), minzoom(other.minzoom) { - if (valueType == AttributePairType::Bool || valueType == AttributePairType::Float) { - floatValue_ = other.floatValue_; + if (valueType == AttributePairType::String) { + stringValue_ = other.stringValue_; return; } - - stringValue_ = other.stringValue_; + + doubleValue_ = other.doubleValue_; } AttributePair& operator=(const AttributePair& other) { @@ -83,12 +87,12 @@ struct AttributePair { valueType = other.valueType; minzoom = other.minzoom; - if (valueType == AttributePairType::Bool || valueType == AttributePairType::Float) { - floatValue_ = other.floatValue_; + if (valueType == AttributePairType::String) { + stringValue_ = other.stringValue_; return *this; } - stringValue_ = other.stringValue_; + doubleValue_ = other.doubleValue_; return *this; } @@ -100,30 +104,25 @@ struct AttributePair { if (valueType != other.valueType) return valueType < other.valueType; if (hasStringValue()) return pooledString() < other.pooledString(); - if (hasBoolValue()) return boolValue() < other.boolValue(); - if (hasFloatValue()) return floatValue() < other.floatValue(); - throw std::runtime_error("Invalid type in attribute store"); + return doubleValue_ < other.doubleValue_; } bool operator==(const AttributePair &other) const { if (minzoom!=other.minzoom || keyIndex!=other.keyIndex || valueType!=other.valueType) return false; - if (valueType == AttributePairType::String) - return stringValue_ == other.stringValue_; - - if (valueType == AttributePairType::Float || valueType == AttributePairType::Bool) - return floatValue_ == other.floatValue_; - - return true; + if (valueType == AttributePairType::String) return stringValue_ == other.stringValue_; + return doubleValue_ == other.doubleValue_; } bool hasStringValue() const { return valueType == AttributePairType::String; } bool hasFloatValue() const { return valueType == AttributePairType::Float; } bool hasBoolValue() const { return valueType == AttributePairType::Bool; } + bool hasIntValue() const { return valueType == AttributePairType::Int; } const PooledString& pooledString() const { return stringValue_; } const std::string stringValue() const { return stringValue_.toString(); } - float floatValue() const { return floatValue_; } - bool boolValue() const { return floatValue_; } + float floatValue() const { return static_cast(doubleValue_); } + bool boolValue() const { return doubleValue_; } + int intValue() const { return static_cast(doubleValue_); } void ensureStringIsOwned(); @@ -162,7 +161,9 @@ struct AttributePair { const char* data = pooledString().data(); boost::hash_range(rv, data, data + pooledString().size()); } else if(hasFloatValue()) - boost::hash_combine(rv, floatValue()); + boost::hash_combine(rv, doubleValue_); + else if(hasIntValue()) + boost::hash_combine(rv, doubleValue_); else if(hasBoolValue()) boost::hash_combine(rv, boolValue()); else { @@ -407,7 +408,8 @@ struct AttributeStore { void finalize(); void addAttribute(AttributeSet& attributeSet, std::string const &key, const protozero::data_view v, char minzoom); - void addAttribute(AttributeSet& attributeSet, std::string const &key, float v, char minzoom); + void addAttribute(AttributeSet& attributeSet, std::string const &key, double v, char minzoom); + void addAttribute(AttributeSet& attributeSet, std::string const &key, int v, char minzoom); void addAttribute(AttributeSet& attributeSet, std::string const &key, bool v, char minzoom); AttributeStore(): diff --git a/include/osm_lua_processing.h b/include/osm_lua_processing.h index 72100635..cab3f1f0 100644 --- a/include/osm_lua_processing.h +++ b/include/osm_lua_processing.h @@ -195,8 +195,9 @@ class OsmLuaProcessing { // Set attributes in a vector tile's Attributes table void Attribute(const std::string &key, const protozero::data_view val, const char minzoom); - void AttributeNumeric(const std::string &key, const float val, const char minzoom); + void AttributeNumeric(const std::string &key, const double val, const char minzoom); void AttributeBoolean(const std::string &key, const bool val, const char minzoom); + void AttributeInteger(const std::string &key, const int val, const char minzoom); void MinZoom(const double z); void ZOrder(const double z); diff --git a/resources/process-debug.lua b/resources/process-debug.lua index 80f875eb..4ea5e629 100644 --- a/resources/process-debug.lua +++ b/resources/process-debug.lua @@ -93,7 +93,7 @@ function node_function() Layer("place", false) Attribute("class", place) MinZoom(mz) - if rank then AttributeNumeric("rank", rank) end + if rank then AttributeInteger("rank", rank) end SetNameAttributes() return end @@ -107,7 +107,7 @@ function node_function() if natural == "peak" or natural == "volcano" then Layer("mountain_peak", false) SetEleAttributes() - AttributeNumeric("rank", 1) + AttributeInteger("rank", 1) Attribute("class", natural) SetNameAttributes() return @@ -256,12 +256,12 @@ function way_function() if linkValues[highway] then splitHighway = split(highway, "_") highway = splitHighway[1] - AttributeNumeric("ramp",1) + AttributeInteger("ramp",1) end local oneway = Find("oneway") if oneway == "yes" or oneway == "1" then - AttributeNumeric("oneway",1) + AttributeInteger("oneway",1) end if oneway == "-1" then -- **** TODO @@ -282,7 +282,7 @@ function way_function() local ref = Find("ref") if ref~="" then Attribute("ref",ref) - AttributeNumeric("ref_length",ref:len()) + AttributeInteger("ref_length",ref:len()) end end @@ -326,7 +326,7 @@ function way_function() else Layer("waterway_detail", false) end - if Find("intermittent")=="yes" then AttributeNumeric("intermittent", 1) else AttributeNumeric("intermittent", 0) end + if Find("intermittent")=="yes" then AttributeInteger("intermittent", 1) else AttributeInteger("intermittent", 0) end Attribute("class", waterway) SetNameAttributes() SetBrunnelAttributes() @@ -419,7 +419,7 @@ function way_function() LayerAsCentroid("poi_detail") SetNameAttributes() if write_name then rank=6 else rank=25 end - AttributeNumeric("rank", rank) + AttributeInteger("rank", rank) end end @@ -437,7 +437,7 @@ function WritePOI(obj,class,subclass,rank) if rank>4 then layer="poi_detail" end LayerAsCentroid(layer) SetNameAttributes(obj) - AttributeNumeric("rank", rank) + AttributeInteger("rank", rank) Attribute("class", class) Attribute("subclass", subclass) end diff --git a/resources/process-example.lua b/resources/process-example.lua index cf3266c2..ccf95766 100644 --- a/resources/process-example.lua +++ b/resources/process-example.lua @@ -38,7 +38,7 @@ function node_function(node) if amenity~="" then Attribute("class",amenity) else Attribute("class",shop) end Attribute("name:latin", Find("name")) - AttributeNumeric("rank", 3) + AttributeInteger("rank", 3) end -- Places go to a "place" layer @@ -48,13 +48,13 @@ function node_function(node) Attribute("class", place) Attribute("name:latin", Find("name")) if place=="city" then - AttributeNumeric("rank", 4) + AttributeInteger("rank", 4) MinZoom(3) elseif place=="town" then - AttributeNumeric("rank", 6) + AttributeInteger("rank", 6) MinZoom(6) else - AttributeNumeric("rank", 9) + AttributeInteger("rank", 9) MinZoom(10) end end @@ -86,7 +86,7 @@ function way_function() if waterway=="stream" or waterway=="river" or waterway=="canal" then Layer("waterway", false) Attribute("class", waterway) - AttributeNumeric("intermittent", 0) + AttributeInteger("intermittent", 0) end -- Lakes and other water polygons diff --git a/resources/process-openmaptiles.lua b/resources/process-openmaptiles.lua index 30aefcae..3158bfba 100644 --- a/resources/process-openmaptiles.lua +++ b/resources/process-openmaptiles.lua @@ -177,8 +177,8 @@ function node_function() Layer("place", false) Attribute("class", place) MinZoom(mz) - if rank then AttributeNumeric("rank", rank) end - if capital then AttributeNumeric("capital", capital) end + if rank then AttributeInteger("rank", rank) end + if capital then AttributeInteger("capital", capital) end if place=="country" then local iso_a2 = Find("ISO3166-1:alpha2") while iso_a2 == "" do @@ -203,7 +203,7 @@ function node_function() if natural == "peak" or natural == "volcano" then Layer("mountain_peak", false) SetEleAttributes() - AttributeNumeric("rank", 1) + AttributeInteger("rank", 1) Attribute("class", natural) SetNameAttributes() return @@ -314,7 +314,7 @@ function write_to_transportation_layer(minzoom, highway_class, subclass, ramp, s if subclass and subclass ~= "" then Attribute("subclass", subclass) end - AttributeNumeric("layer", tonumber(Find("layer")) or 0, accessMinzoom) + AttributeInteger("layer", tonumber(Find("layer")) or 0, accessMinzoom) SetBrunnelAttributes() -- We do not write any other attributes for areas. if is_area then @@ -322,7 +322,7 @@ function write_to_transportation_layer(minzoom, highway_class, subclass, ramp, s return end MinZoom(minzoom) - if ramp then AttributeNumeric("ramp",1) end + if ramp then AttributeInteger("ramp",1) end -- Service if (is_rail or highway_class == "service") and (service and service ~="") then Attribute("service", service) end @@ -331,7 +331,7 @@ function write_to_transportation_layer(minzoom, highway_class, subclass, ramp, s if is_road then local oneway = Find("oneway") if oneway == "yes" or oneway == "1" then - AttributeNumeric("oneway",1) + AttributeInteger("oneway",1) end if oneway == "-1" then -- **** TODO @@ -398,7 +398,7 @@ function way_function() local pop = tonumber(Find("population")) or 0 local capital = capitalLevel(Find("capital")) local rank = calcRank(place, pop, nil) - if rank then AttributeNumeric("rank", rank) end + if rank then AttributeInteger("rank", rank) end SetNameAttributes() end @@ -431,14 +431,14 @@ function way_function() end Layer("boundary",false) - AttributeNumeric("admin_level", admin_level) + AttributeInteger("admin_level", admin_level) MinZoom(mz) -- disputed status (0 or 1). some styles need to have the 0 to show it. local disputed = Find("disputed") if disputed=="yes" then - AttributeNumeric("disputed", 1) + AttributeInteger("disputed", 1) else - AttributeNumeric("disputed", 0) + AttributeInteger("disputed", 0) end end @@ -543,7 +543,7 @@ function way_function() local ref = Find("ref") if ref~="" then Attribute("ref",ref) - AttributeNumeric("ref_length",ref:len()) + AttributeInteger("ref_length",ref:len()) end end end @@ -623,7 +623,7 @@ function way_function() else Layer("waterway_detail", false) end - if Find("intermittent")=="yes" then AttributeNumeric("intermittent", 1) else AttributeNumeric("intermittent", 0) end + if Find("intermittent")=="yes" then AttributeInteger("intermittent", 1) else AttributeInteger("intermittent", 0) end Attribute("class", waterway) SetNameAttributes() SetBrunnelAttributes() @@ -723,7 +723,7 @@ function way_function() LayerAsCentroid("poi_detail") SetNameAttributes() if write_name then rank=6 else rank=25 end - AttributeNumeric("rank", rank) + AttributeInteger("rank", rank) end end @@ -751,17 +751,17 @@ function WritePOI(class,subclass,rank) if rank>4 then layer="poi_detail" end LayerAsCentroid(layer) SetNameAttributes() - AttributeNumeric("rank", rank) + AttributeInteger("rank", rank) Attribute("class", class) Attribute("subclass", subclass) -- layer defaults to 0 - AttributeNumeric("layer", tonumber(Find("layer")) or 0) + AttributeInteger("layer", tonumber(Find("layer")) or 0) -- indoor defaults to false AttributeBoolean("indoor", (Find("indoor") == "yes")) -- level has no default local level = tonumber(Find("level")) if level then - AttributeNumeric("level", level) + AttributeInteger("level", level) end end diff --git a/src/attribute_store.cpp b/src/attribute_store.cpp index facafdbf..73ed4775 100644 --- a/src/attribute_store.cpp +++ b/src/attribute_store.cpp @@ -59,8 +59,7 @@ const std::string& AttributeKeyStore::getKeyUnsafe(uint16_t index) const { void AttributePair::ensureStringIsOwned() { // Before we store an AttributePair in our long-term storage, we need // to make sure it's not pointing to a non-long-lived std::string. - if (valueType == AttributePairType::Bool || valueType == AttributePairType::Float) - return; + if (valueType != AttributePairType::String) return; stringValue_.ensureStringIsOwned(); } @@ -251,11 +250,16 @@ void AttributeStore::addAttribute(AttributeSet& attributeSet, std::string const bool isHot = true; // All bools are eligible to be hot pairs attributeSet.addPair(pairStore.addPair(kv, isHot)); } -void AttributeStore::addAttribute(AttributeSet& attributeSet, std::string const &key, float v, char minzoom) { +void AttributeStore::addAttribute(AttributeSet& attributeSet, std::string const &key, double v, char minzoom) { AttributePair kv(keyStore.key2index(key),v,minzoom); bool isHot = v >= 0 && v <= 25 && ceil(v) == v; // Whole numbers in 0..25 are eligible to be hot pairs attributeSet.addPair(pairStore.addPair(kv, isHot)); } +void AttributeStore::addAttribute(AttributeSet& attributeSet, std::string const &key, int v, char minzoom) { + AttributePair kv(keyStore.key2index(key),v,minzoom); + bool isHot = v >= 0 && v <= 25; + attributeSet.addPair(pairStore.addPair(kv, isHot)); +} void AttributeSet::finalize() { // Ensure that values are sorted, giving us a canonical representation, diff --git a/src/geojson_processor.cpp b/src/geojson_processor.cpp index 25a5e72d..6a557511 100644 --- a/src/geojson_processor.cpp +++ b/src/geojson_processor.cpp @@ -240,10 +240,10 @@ AttributeIndex GeoJSONProcessor::readProperties(const rapidjson::Value &pr, bool layer.attributeMap[key] = 0; } else if (val.isType()) { if (key=="_minzoom") { minzoom=val; continue; } - attributeStore.addAttribute(attributes, key, (float)val, 0); + attributeStore.addAttribute(attributes, key, (int)val, 0); layer.attributeMap[key] = 1; } else if (val.isType()) { - attributeStore.addAttribute(attributes, key, (float)val, 0); + attributeStore.addAttribute(attributes, key, (double)val, 0); layer.attributeMap[key] = 1; } else if (val.isType()) { attributeStore.addAttribute(attributes, key, (bool)val, 0); @@ -267,7 +267,7 @@ AttributeIndex GeoJSONProcessor::readProperties(const rapidjson::Value &pr, bool attributeStore.addAttribute(attributes, key, it->value.GetBool(), 0); layer.attributeMap[key] = 2; } else if (it->value.IsNumber()) { - attributeStore.addAttribute(attributes, key, it->value.GetFloat(), 0); + attributeStore.addAttribute(attributes, key, it->value.GetDouble(), 0); layer.attributeMap[key] = 1; } else { // something different, so coerce to string diff --git a/src/osm_lua_processing.cpp b/src/osm_lua_processing.cpp index cba5948c..6778e946 100644 --- a/src/osm_lua_processing.cpp +++ b/src/osm_lua_processing.cpp @@ -270,8 +270,12 @@ OsmLuaProcessing::OsmLuaProcessing( [](const std::string &key, const protozero::data_view val, const char minzoom) { osmLuaProcessing->Attribute(key, val, minzoom); } ); luaState["AttributeNumeric"] = kaguya::overload( - [](const std::string &key, const float val) { osmLuaProcessing->AttributeNumeric(key, val, 0); }, - [](const std::string &key, const float val, const char minzoom) { osmLuaProcessing->AttributeNumeric(key, val, minzoom); } + [](const std::string &key, const double val) { osmLuaProcessing->AttributeNumeric(key, val, 0); }, + [](const std::string &key, const double val, const char minzoom) { osmLuaProcessing->AttributeNumeric(key, val, minzoom); } + ); + luaState["AttributeInteger"] = kaguya::overload( + [](const std::string &key, const int val) { osmLuaProcessing->AttributeInteger(key, val, 0); }, + [](const std::string &key, const int val, const char minzoom) { osmLuaProcessing->AttributeInteger(key, val, minzoom); } ); luaState["AttributeBoolean"] = kaguya::overload( [](const std::string &key, const bool val) { osmLuaProcessing->AttributeBoolean(key, val, 0); }, @@ -919,7 +923,7 @@ void OsmLuaProcessing::Attribute(const string &key, const protozero::data_view v setVectorLayerMetadata(outputs.back().first.layer, key, 0); } -void OsmLuaProcessing::AttributeNumeric(const string &key, const float val, const char minzoom) { +void OsmLuaProcessing::AttributeNumeric(const string &key, const double val, const char minzoom) { if (outputs.size()==0) { ProcessingError("Can't add Attribute if no Layer set"); return; } removeAttributeIfNeeded(key); attributeStore.addAttribute(outputs.back().second, key, val, minzoom); @@ -933,6 +937,13 @@ void OsmLuaProcessing::AttributeBoolean(const string &key, const bool val, const setVectorLayerMetadata(outputs.back().first.layer, key, 2); } +void OsmLuaProcessing::AttributeInteger(const string &key, const int val, const char minzoom) { + if (outputs.size()==0) { ProcessingError("Can't add Attribute if no Layer set"); return; } + removeAttributeIfNeeded(key); + attributeStore.addAttribute(outputs.back().second, key, val, minzoom); + setVectorLayerMetadata(outputs.back().first.layer, key, 3); +} + // Set minimum zoom void OsmLuaProcessing::MinZoom(const double z) { if (outputs.size()==0) { ProcessingError("Can't set minimum zoom if no Layer set"); return; } diff --git a/src/output_object.cpp b/src/output_object.cpp index e0097a7b..93eef495 100644 --- a/src/output_object.cpp +++ b/src/output_object.cpp @@ -49,6 +49,9 @@ void OutputObject::writeAttributes( fbuilder.add_property(key, it->stringValue()); } else if (it->hasBoolValue()) { fbuilder.add_property(key, it->boolValue()); + } else if (it->hasIntValue()) { + // could potentially add ,vtzero::sint_value_type(2) to force sint encoding (efficient for -ve ints) + fbuilder.add_property(key, it->intValue()); } else if (it->hasFloatValue()) { fbuilder.add_property(key, it->floatValue()); } diff --git a/src/shp_processor.cpp b/src/shp_processor.cpp index 9e56b2ba..d1ed8ffc 100644 --- a/src/shp_processor.cpp +++ b/src/shp_processor.cpp @@ -70,10 +70,10 @@ AttributeIndex ShpProcessor::readShapefileAttributes( layer.attributeMap[key] = 0; } else if (val.isType()) { if (key=="_minzoom") { minzoom=val; continue; } - attributeStore.addAttribute(attributes, key, (float)val, 0); + attributeStore.addAttribute(attributes, key, (int)val, 0); layer.attributeMap[key] = 1; } else if (val.isType()) { - attributeStore.addAttribute(attributes, key, (float)val, 0); + attributeStore.addAttribute(attributes, key, (double)val, 0); layer.attributeMap[key] = 1; } else if (val.isType()) { attributeStore.addAttribute(attributes, key, (bool)val, 0); @@ -88,10 +88,10 @@ AttributeIndex ShpProcessor::readShapefileAttributes( int pos = it.first; string key = it.second; switch (columnTypeMap[pos]) { - case 1: attributeStore.addAttribute(attributes, key, (float)DBFReadIntegerAttribute(dbf, recordNum, pos), 0); + case 1: attributeStore.addAttribute(attributes, key, (int)DBFReadIntegerAttribute(dbf, recordNum, pos), 0); layer.attributeMap[key] = 1; break; - case 2: attributeStore.addAttribute(attributes, key, static_cast(DBFReadDoubleAttribute(dbf, recordNum, pos)), 0); + case 2: attributeStore.addAttribute(attributes, key, (double)DBFReadDoubleAttribute(dbf, recordNum, pos), 0); layer.attributeMap[key] = 1; break; case 3: attributeStore.addAttribute(attributes, key, strcmp(DBFReadStringAttribute(dbf, recordNum, pos), "T")==0, 0); diff --git a/test/attribute_store.test.cpp b/test/attribute_store.test.cpp index aa3c842f..6058bc89 100644 --- a/test/attribute_store.test.cpp +++ b/test/attribute_store.test.cpp @@ -14,14 +14,15 @@ MU_TEST(test_attribute_store) { store.addAttribute(s1, "str2", std::string("a very long string"), 14); store.addAttribute(s1, "bool1", false, 0); store.addAttribute(s1, "bool2", true, 0); - store.addAttribute(s1, "float1", (float)42.0, 4); + store.addAttribute(s1, "double1", (double)42.0, 4); + store.addAttribute(s1, "int1", 43, 8); const auto s1Index = store.add(s1); mu_check(store.size() == 1); const auto s1Pairs = store.getUnsafe(s1Index); - mu_check(s1Pairs.size() == 5); + mu_check(s1Pairs.size() == 6); const auto str1 = std::find_if(s1Pairs.begin(), s1Pairs.end(), [&store](auto ap) { return ap->keyIndex == store.keyStore.key2index("str1"); }); @@ -51,13 +52,21 @@ MU_TEST(test_attribute_store) { mu_check((*bool2)->hasBoolValue()); mu_check((*bool2)->boolValue() == true); - const auto float1 = std::find_if(s1Pairs.begin(), s1Pairs.end(), [&store](auto ap) { - return ap->keyIndex == store.keyStore.key2index("float1"); + const auto double1 = std::find_if(s1Pairs.begin(), s1Pairs.end(), [&store](auto ap) { + return ap->keyIndex == store.keyStore.key2index("double1"); }); - mu_check(float1 != s1Pairs.end()); - mu_check((*float1)->hasFloatValue()); - mu_check((*float1)->floatValue() == 42); - mu_check((*float1)->minzoom == 4); + mu_check(double1 != s1Pairs.end()); + mu_check((*double1)->hasFloatValue()); + mu_check((*double1)->floatValue() == 42); + mu_check((*double1)->minzoom == 4); + + const auto int1 = std::find_if(s1Pairs.begin(), s1Pairs.end(), [&store](auto ap) { + return ap->keyIndex == store.keyStore.key2index("int1"); + }); + mu_check(int1 != s1Pairs.end()); + mu_check((*int1)->hasIntValue()); + mu_check((*int1)->intValue() == 43); + mu_check((*int1)->minzoom == 8); } MU_TEST(test_attribute_store_reuses) {