Reduce memory use of FeatureIndex (#2364)

This commit is contained in:
Tim Sylvester
2024-05-16 07:17:24 -07:00
committed by GitHub
parent aff5693fb9
commit b812e97aaf
15 changed files with 211 additions and 64 deletions

View File

@@ -24,7 +24,7 @@ void FileSourceRequest::onCancel(std::function<void()>&& callback) {
void FileSourceRequest::setResponse(const Response& response) {
// Copy, because calling the callback will sometimes self
// destroy this object. We cannot move because this method
// can be called more than one.
// can be called more than once.
auto callback = responseCallback;
callback(response);
}

View File

@@ -33,6 +33,90 @@ mbgl::Point<double> project(const mbgl::LatLng& coordinate, const mbgl::Transfor
namespace mbgl {
constexpr auto expectedUniqueLayerIDs = 10;
constexpr auto expectedUniqueLeaderIDs = 30;
RefIndexedSubfeature::RefIndexedSubfeature(std::size_t index_,
const std::string& sourceLayerName_,
const std::string& bucketName_,
size_t sortIndex_,
uint32_t bucketInstanceId_,
uint16_t collisionGroupId_)
: index(index_),
sortIndex(sortIndex_),
sourceLayerName(sourceLayerName_),
bucketLeaderID(bucketName_),
bucketInstanceId(bucketInstanceId_),
collisionGroupId(collisionGroupId_) {}
IndexedSubfeature::IndexedSubfeature(const RefIndexedSubfeature& other)
: IndexedSubfeature(other, other.getBucketInstanceId(), other.getCollisionGroupId()) {}
IndexedSubfeature::IndexedSubfeature(const RefIndexedSubfeature& other,
uint32_t bucketInstanceId_,
uint16_t collisionGroupId_)
: IndexedSubfeature(other.getIndex(),
other.getSourceLayerName(),
other.getBucketLeaderID(),
other.getSortIndex(),
bucketInstanceId_,
collisionGroupId_) {}
IndexedSubfeature::IndexedSubfeature(const IndexedSubfeature& other)
: IndexedSubfeature(other.getIndex(),
other.sourceLayerName,
other.bucketLeaderID,
other.getSortIndex(),
other.getBucketInstanceId(),
other.getCollisionGroupId()) {}
IndexedSubfeature::IndexedSubfeature(IndexedSubfeature&& other)
: IndexedSubfeature(other.getIndex(),
std::move(other.sourceLayerName),
std::move(other.bucketLeaderID),
other.getSortIndex(),
other.getBucketInstanceId(),
other.getCollisionGroupId()) {}
IndexedSubfeature::IndexedSubfeature(std::size_t index_,
std::string sourceLayerName_,
std::string bucketName_,
size_t sortIndex_,
uint32_t bucketInstanceId_,
uint16_t collisionGroupId_)
: RefIndexedSubfeature(index_,
this->sourceLayerNameCopy,
this->bucketLeaderIDCopy,
sortIndex_,
bucketInstanceId_,
collisionGroupId_),
sourceLayerNameCopy(std::move(sourceLayerName_)),
bucketLeaderIDCopy(std::move(bucketName_)) {}
IndexedSubfeature& IndexedSubfeature::operator=(const IndexedSubfeature& other) {
index = other.index;
sourceLayerName = sourceLayerNameCopy;
bucketLeaderID = bucketLeaderIDCopy;
sortIndex = other.sortIndex;
bucketInstanceId = other.bucketInstanceId;
collisionGroupId = other.collisionGroupId;
sourceLayerNameCopy = other.sourceLayerNameCopy;
bucketLeaderIDCopy = other.bucketLeaderIDCopy;
return *this;
}
IndexedSubfeature& IndexedSubfeature::operator=(IndexedSubfeature&& other) {
index = other.index;
sourceLayerName = sourceLayerNameCopy;
bucketLeaderID = bucketLeaderIDCopy;
sortIndex = other.sortIndex;
bucketInstanceId = other.bucketInstanceId;
collisionGroupId = other.collisionGroupId;
sourceLayerNameCopy = std::move(other.sourceLayerNameCopy);
bucketLeaderIDCopy = std::move(other.bucketLeaderIDCopy);
return *this;
}
FeatureIndex::FeatureIndex(std::unique_ptr<const GeometryTileData> tileData_)
: grid(util::EXTENT, util::EXTENT, util::EXTENT / 16), // 16x16 grid -> 32px cell
tileData(std::move(tileData_)) {}
@@ -41,12 +125,22 @@ void FeatureIndex::insert(const GeometryCollection& geometries,
std::size_t index,
const std::string& sourceLayerName,
const std::string& bucketLeaderID) {
if (uniqueLayerIDs.empty()) {
uniqueLayerIDs.reserve(expectedUniqueLayerIDs);
}
const std::string& emplacedLayerName = *uniqueLayerIDs.insert(sourceLayerName).first;
if (bucketLayerIDs.empty()) {
bucketLayerIDs.reserve(expectedUniqueLeaderIDs);
}
const std::string& emplacedLeaderID =
bucketLayerIDs.insert(std::make_pair(bucketLeaderID, std::vector<std::string>{})).first->first;
auto featureSortIndex = sortIndex++;
for (const auto& ring : geometries) {
auto envelope = mapbox::geometry::envelope(ring);
const auto envelope = mapbox::geometry::envelope(ring);
if (envelope.min.x < util::EXTENT && envelope.min.y < util::EXTENT && envelope.max.x >= 0 &&
envelope.max.y >= 0) {
grid.insert(IndexedSubfeature(index, sourceLayerName, bucketLeaderID, featureSortIndex),
grid.insert(RefIndexedSubfeature(index, emplacedLayerName, emplacedLeaderID, featureSortIndex),
{convertPoint<float>(envelope.min), convertPoint<float>(envelope.max)});
}
}
@@ -74,17 +168,17 @@ void FeatureIndex::query(std::unordered_map<std::string, std::vector<Feature>>&
// Query the grid index
mapbox::geometry::box<int16_t> box = mapbox::geometry::envelope(queryGeometry);
std::vector<IndexedSubfeature> features = grid.query(
std::vector<RefIndexedSubfeature> features = grid.query(
{convertPoint<float>(box.min - additionalPadding), convertPoint<float>(box.max + additionalPadding)});
std::sort(features.begin(), features.end(), [](const IndexedSubfeature& a, const IndexedSubfeature& b) {
return a.sortIndex > b.sortIndex;
std::sort(features.begin(), features.end(), [](const RefIndexedSubfeature& a, const RefIndexedSubfeature& b) {
return a.getSortIndex() > b.getSortIndex();
});
size_t previousSortIndex = std::numeric_limits<size_t>::max();
for (const auto& indexedFeature : features) {
// If this feature is the same as the previous feature, skip it.
if (indexedFeature.sortIndex == previousSortIndex) continue;
previousSortIndex = indexedFeature.sortIndex;
if (indexedFeature.getSortIndex() == previousSortIndex) continue;
previousSortIndex = indexedFeature.getSortIndex();
addFeature(result,
indexedFeature,
@@ -109,11 +203,12 @@ std::unordered_map<std::string, std::vector<Feature>> FeatureIndex::lookupSymbol
if (!tileData) {
return result;
}
std::vector<IndexedSubfeature> sortedFeatures(symbolFeatures.begin(), symbolFeatures.end());
std::vector<std::reference_wrapper<const RefIndexedSubfeature>> sortedFeatures(symbolFeatures.begin(),
symbolFeatures.end());
std::sort(sortedFeatures.begin(),
sortedFeatures.end(),
[featureSortOrder](const IndexedSubfeature& a, const IndexedSubfeature& b) {
[featureSortOrder](const RefIndexedSubfeature& a, const RefIndexedSubfeature& b) {
// Same idea as the non-symbol sort order, but symbol features may
// have changed their sort order since their corresponding
// IndexedSubfeature was added to the CollisionIndex The
@@ -124,15 +219,15 @@ std::unordered_map<std::string, std::vector<Feature>> FeatureIndex::lookupSymbol
// "top-to-bottom" rendering order (aka last-to-first).
// Actually there can be multiple symbol instances per feature, so
// we sort each feature based on the first matching symbol instance.
auto sortedA = std::find(featureSortOrder->begin(), featureSortOrder->end(), a.index);
auto sortedB = std::find(featureSortOrder->begin(), featureSortOrder->end(), b.index);
auto sortedA = std::find(featureSortOrder->begin(), featureSortOrder->end(), a.getIndex());
auto sortedB = std::find(featureSortOrder->begin(), featureSortOrder->end(), b.getIndex());
assert(sortedA != featureSortOrder->end());
assert(sortedB != featureSortOrder->end());
return sortedA > sortedB;
} else {
// Bucket hasn't been re-sorted based on angle, so use same
// "reverse of appearance in source data" logic as non-symboles
return a.sortIndex > b.sortIndex;
return a.getSortIndex() > b.getSortIndex();
}
});
@@ -153,7 +248,7 @@ std::unordered_map<std::string, std::vector<Feature>> FeatureIndex::lookupSymbol
}
void FeatureIndex::addFeature(std::unordered_map<std::string, std::vector<Feature>>& result,
const IndexedSubfeature& indexedFeature,
const RefIndexedSubfeature& indexedFeature,
const RenderedQueryOptions& options,
const CanonicalTileID& tileID,
const std::unordered_map<std::string, const RenderLayer*>& layers,
@@ -166,7 +261,7 @@ void FeatureIndex::addFeature(std::unordered_map<std::string, std::vector<Featur
std::unique_ptr<GeometryTileLayer> sourceLayer;
std::unique_ptr<GeometryTileFeature> geometryTileFeature;
for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketLeaderID)) {
for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.getBucketLeaderID())) {
const auto it = layers.find(layerID);
if (it == layers.end()) {
continue;
@@ -175,10 +270,10 @@ void FeatureIndex::addFeature(std::unordered_map<std::string, std::vector<Featur
const RenderLayer* renderLayer = it->second;
if (!geometryTileFeature) {
sourceLayer = tileData->getLayer(indexedFeature.sourceLayerName);
sourceLayer = tileData->getLayer(indexedFeature.getSourceLayerName());
assert(sourceLayer);
geometryTileFeature = sourceLayer->getFeature(indexedFeature.index);
geometryTileFeature = sourceLayer->getFeature(indexedFeature.getIndex());
assert(geometryTileFeature);
}
FeatureState state;
@@ -226,6 +321,8 @@ std::optional<GeometryCoordinates> FeatureIndex::translateQueryGeometry(const Ge
}
GeometryCoordinates translated;
translated.reserve(queryGeometry.size());
for (const auto& p : queryGeometry) {
translated.push_back(p - translateVec);
}
@@ -233,6 +330,9 @@ std::optional<GeometryCoordinates> FeatureIndex::translateQueryGeometry(const Ge
}
void FeatureIndex::setBucketLayerIDs(const std::string& bucketLeaderID, const std::vector<std::string>& layerIDs) {
if (bucketLayerIDs.empty()) {
bucketLayerIDs.reserve(expectedUniqueLeaderIDs);
}
bucketLayerIDs[bucketLeaderID] = layerIDs;
}
@@ -249,6 +349,7 @@ void DynamicFeatureIndex::query(std::unordered_map<std::string, std::vector<Feat
const Point<int64_t> coord = {int64_t(pm.x), int64_t(pm.y)};
mbgl::updateBBox(queryBox, coord);
}
for (const auto& f : features) {
// hit testing
mbgl::GeometryBBox<int64_t> featureBox = DefaultWithinBBox;

View File

@@ -21,34 +21,69 @@ class SourceFeatureState;
class CollisionIndex;
class IndexedSubfeature {
/// An indexed element within a feature index.
/// This version holds a reference to the strings within the index itself to avoid making tens of thousands of
/// unnecessary copies of them. As a result, its lifetime cannot exceed that of the index.
class RefIndexedSubfeature {
public:
IndexedSubfeature() = delete;
IndexedSubfeature(std::size_t index_, std::string sourceLayerName_, std::string bucketName_, size_t sortIndex_)
: index(index_),
sourceLayerName(std::move(sourceLayerName_)),
bucketLeaderID(std::move(bucketName_)),
sortIndex(sortIndex_),
bucketInstanceId(0),
collisionGroupId(0) {}
RefIndexedSubfeature() = delete;
RefIndexedSubfeature(RefIndexedSubfeature&&) = default;
RefIndexedSubfeature(const RefIndexedSubfeature&) = default;
RefIndexedSubfeature(std::size_t index_,
const std::string& sourceLayerName_,
const std::string& bucketName_,
size_t sortIndex_,
uint32_t bucketInstanceId_ = 0,
uint16_t collisionGroupId_ = 0);
IndexedSubfeature(const IndexedSubfeature& other, uint32_t bucketInstanceId_, uint16_t collisionGroupId_)
: index(other.index),
sourceLayerName(other.sourceLayerName),
bucketLeaderID(other.bucketLeaderID),
sortIndex(other.sortIndex),
bucketInstanceId(bucketInstanceId_),
collisionGroupId(collisionGroupId_) {}
RefIndexedSubfeature& operator=(const RefIndexedSubfeature&) = default;
RefIndexedSubfeature& operator=(RefIndexedSubfeature&&) = default;
size_t getIndex() const { return index; }
size_t getSortIndex() const { return sortIndex; }
const std::string& getSourceLayerName() const { return sourceLayerName.get(); }
const std::string& getBucketLeaderID() const { return bucketLeaderID.get(); }
uint32_t getBucketInstanceId() const { return bucketInstanceId; }
uint16_t getCollisionGroupId() const { return collisionGroupId; }
protected:
size_t index;
std::string sourceLayerName;
std::string bucketLeaderID;
size_t sortIndex;
std::reference_wrapper<const std::string> sourceLayerName;
std::reference_wrapper<const std::string> bucketLeaderID;
// Only used for symbol features
uint32_t bucketInstanceId;
uint16_t collisionGroupId;
};
/// This version of an indexed feature has copies of the necessary strings, so that it can be used outside the index.
class IndexedSubfeature : public RefIndexedSubfeature {
public:
IndexedSubfeature(const RefIndexedSubfeature&);
IndexedSubfeature(const RefIndexedSubfeature&, uint32_t bucketInstanceId_, uint16_t collisionGroupId_);
IndexedSubfeature(const IndexedSubfeature&);
IndexedSubfeature(IndexedSubfeature&&);
IndexedSubfeature(std::size_t index_,
std::string sourceLayerName_,
std::string bucketName_,
size_t sortIndex_,
uint32_t bucketInstanceId_ = 0,
uint16_t collisionGroupId_ = 0);
IndexedSubfeature& operator=(const IndexedSubfeature&);
IndexedSubfeature& operator=(IndexedSubfeature&&);
private:
std::string sourceLayerNameCopy;
std::string bucketLeaderIDCopy;
};
using FeatureSortOrder = std::shared_ptr<const std::vector<size_t>>;
class DynamicFeatureIndex {
@@ -112,7 +147,7 @@ public:
private:
void addFeature(std::unordered_map<std::string, std::vector<Feature>>& result,
const IndexedSubfeature&,
const RefIndexedSubfeature&,
const RenderedQueryOptions& options,
const CanonicalTileID&,
const std::unordered_map<std::string, const RenderLayer*>&,
@@ -122,10 +157,15 @@ private:
const mat4& posMatrix,
const SourceFeatureState* sourceFeatureState) const;
GridIndex<IndexedSubfeature> grid;
GridIndex<RefIndexedSubfeature> grid;
unsigned int sortIndex = 0;
// mbgl::unordered_* cannot be used here, as we rely on holding references to elements:
// 22.2.7 Unordered associative containers [unord.req]
// The insert and emplace members shall not affect the validity of references to
// container elements, but may invalidate all iterators to the container.
std::unordered_map<std::string, std::vector<std::string>> bucketLayerIDs;
std::unordered_set<std::string> uniqueLayerIDs;
std::unique_ptr<const GeometryTileData> tileData;
};
} // namespace mbgl

View File

@@ -87,7 +87,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
const float iconBoxScale,
const float iconPadding,
const std::array<float, 2>& iconOffset_,
const IndexedSubfeature& indexedFeature,
const RefIndexedSubfeature& indexedFeature,
const std::size_t layoutFeatureIndex_,
const std::size_t dataFeatureIndex_,
std::u16string key_,

View File

@@ -66,7 +66,7 @@ public:
float iconBoxScale,
float iconPadding,
const std::array<float, 2>& iconOffset,
const IndexedSubfeature& indexedFeature,
const RefIndexedSubfeature& indexedFeature,
std::size_t layoutFeatureIndex,
std::size_t dataFeatureIndex,
std::u16string key,

View File

@@ -1206,13 +1206,15 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
// We'll be processing renderables across tiles, potentially out-of-order, so keep
// track of some things by tile ID so we don't have to re-build them multiple times.
using RawVertexVec = std::vector<std::uint8_t>; // <int16_t, 4>
using RawVertexVec = std::vector<std::uint8_t>; // raw buffer for vertexes of <int16_t, 4>
struct TileInfo {
RawVertexVec textVertices, iconVertices;
gfx::DrawableTweakerPtr textTweaker, iconTweaker;
gfx::UniformBufferPtr textInterp, iconInterp;
};
std::unordered_map<UnwrappedTileID, TileInfo> tileCache;
tileCache.reserve(renderTiles->size());
for (auto& group : renderableSegments) {
const auto& renderable = group.renderable;

View File

@@ -87,7 +87,7 @@ public:
const float boxScale,
const float padding,
const style::SymbolPlacementType placement,
const IndexedSubfeature& indexedFeature_,
const RefIndexedSubfeature& indexedFeature_,
const float overscaling,
const float rotate)
: CollisionFeature(line,
@@ -117,7 +117,7 @@ public:
std::optional<PositionedIcon> shapedIcon,
const float boxScale,
const float padding,
const IndexedSubfeature& indexedFeature_,
const RefIndexedSubfeature& indexedFeature_,
const float rotate)
: CollisionFeature(line,
anchor,

View File

@@ -159,7 +159,7 @@ std::pair<bool, bool> CollisionIndex::placeFeature(
const bool pitchWithMap,
const bool collisionDebug,
const std::optional<CollisionBoundaries>& avoidEdges,
const std::optional<std::function<bool(const IndexedSubfeature&)>>& collisionGroupPredicate,
const std::optional<std::function<bool(const RefIndexedSubfeature&)>>& collisionGroupPredicate,
std::vector<ProjectedCollisionBox>& projectedBoxes) {
assert(projectedBoxes.empty());
if (!feature.alongLine) {
@@ -202,7 +202,7 @@ std::pair<bool, bool> CollisionIndex::placeLineFeature(
const bool pitchWithMap,
const bool collisionDebug,
const std::optional<CollisionBoundaries>& avoidEdges,
const std::optional<std::function<bool(const IndexedSubfeature&)>>& collisionGroupPredicate,
const std::optional<std::function<bool(const RefIndexedSubfeature&)>>& collisionGroupPredicate,
std::vector<ProjectedCollisionBox>& projectedBoxes) {
assert(feature.alongLine);
assert(projectedBoxes.empty());
@@ -340,10 +340,10 @@ void CollisionIndex::insertFeature(const CollisionFeature& feature,
}
if (ignorePlacement) {
ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
ignoredGrid.insert(IndexedSubfeature{feature.indexedFeature, bucketInstanceId, collisionGroupId},
circle.circle());
} else {
collisionGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
collisionGrid.insert(IndexedSubfeature{feature.indexedFeature, bucketInstanceId, collisionGroupId},
circle.circle());
}
}
@@ -352,10 +352,10 @@ void CollisionIndex::insertFeature(const CollisionFeature& feature,
auto& box = projectedBoxes[0];
assert(box.isBox());
if (ignorePlacement) {
ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
ignoredGrid.insert(IndexedSubfeature{feature.indexedFeature, bucketInstanceId, collisionGroupId},
box.box());
} else {
collisionGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
collisionGrid.insert(IndexedSubfeature{feature.indexedFeature, bucketInstanceId, collisionGroupId},
box.box());
}
}
@@ -398,23 +398,25 @@ std::unordered_map<uint32_t, std::vector<IndexedSubfeature>> CollisionIndex::que
std::vector<QueryResult> features = collisionGrid.queryWithBoxes(envelope);
std::vector<QueryResult> ignoredFeatures = ignoredGrid.queryWithBoxes(envelope);
features.insert(features.end(), ignoredFeatures.begin(), ignoredFeatures.end());
features.insert(features.end(),
std::make_move_iterator(ignoredFeatures.begin()),
std::make_move_iterator(ignoredFeatures.end()));
std::unordered_map<uint32_t, std::unordered_set<size_t>> seenBuckets;
mbgl::unordered_map<uint32_t, mbgl::unordered_set<size_t>> seenBuckets;
for (auto& queryResult : features) {
auto& feature = queryResult.first;
auto& bbox = queryResult.second;
// Skip already seen features.
auto& seenFeatures = seenBuckets[feature.bucketInstanceId];
if (seenFeatures.find(feature.index) != seenFeatures.end()) continue;
auto& seenFeatures = seenBuckets[feature.getBucketInstanceId()];
if (seenFeatures.find(feature.getIndex()) != seenFeatures.end()) continue;
if (!polygonIntersectsBox(gridQuery, bbox)) {
continue;
}
seenFeatures.insert(feature.index);
result[feature.bucketInstanceId].push_back(feature);
seenFeatures.insert(feature.getIndex());
result[feature.getBucketInstanceId()].push_back(feature);
}
return result;

View File

@@ -48,7 +48,7 @@ public:
bool pitchWithMap,
bool collisionDebug,
const std::optional<CollisionBoundaries>& avoidEdges,
const std::optional<std::function<bool(const IndexedSubfeature&)>>& collisionGroupPredicate,
const std::optional<std::function<bool(const RefIndexedSubfeature&)>>& collisionGroupPredicate,
std::vector<ProjectedCollisionBox>& /*out*/
);
@@ -84,7 +84,7 @@ private:
bool pitchWithMap,
bool collisionDebug,
const std::optional<CollisionBoundaries>& avoidEdges,
const std::optional<std::function<bool(const IndexedSubfeature&)>>& collisionGroupPredicate,
const std::optional<std::function<bool(const RefIndexedSubfeature&)>>& collisionGroupPredicate,
std::vector<ProjectedCollisionBox>& /*out*/
);

View File

@@ -49,8 +49,8 @@ const CollisionGroups::CollisionGroup& CollisionGroups::get(const std::string& s
collisionGroups.emplace(
sourceID,
CollisionGroup(nextGroupID,
std::optional<Predicate>([nextGroupID](const IndexedSubfeature& feature) -> bool {
return feature.collisionGroupId == nextGroupID;
std::optional<Predicate>([nextGroupID](const RefIndexedSubfeature& feature) -> bool {
return feature.getCollisionGroupId() == nextGroupID;
})));
}
return collisionGroups[sourceID];

View File

@@ -77,7 +77,7 @@ struct RetainedQueryData {
class CollisionGroups {
public:
using Predicate = std::function<bool(const IndexedSubfeature&)>;
using Predicate = std::function<bool(const RefIndexedSubfeature&)>;
using CollisionGroup = std::pair<uint16_t, std::optional<Predicate>>;
CollisionGroups(const bool crossSourceCollisions_)

View File

@@ -363,7 +363,9 @@ void GeometryTileWorker::parse() {
ImageDependencies imageDependencies;
// Create render layers and group by layout
std::unordered_map<std::string, std::vector<Immutable<style::LayerProperties>>> groupMap;
mbgl::unordered_map<std::string, std::vector<Immutable<style::LayerProperties>>> groupMap;
groupMap.reserve(layers->size());
for (auto layer : *layers) {
groupMap[layoutKey(*layer->baseImpl)].push_back(std::move(layer));
}

View File

@@ -3,6 +3,6 @@
namespace mbgl {
template class GridIndex<IndexedSubfeature>;
template class GridIndex<RefIndexedSubfeature>;
} // namespace mbgl

View File

@@ -141,7 +141,7 @@ void GridIndex<T>::insert(T&& t, const BBox& bbox) {
}
}
boxElements.emplace_back(t, bbox);
boxElements.emplace_back(std::move(t), bbox);
}
template <class T>
@@ -164,7 +164,7 @@ void GridIndex<T>::insert(T&& t, const BCircle& bcircle) {
}
}
circleElements.emplace_back(t, bcircle);
circleElements.emplace_back(std::move(t), bcircle);
}
template <class T>

View File

@@ -10,7 +10,7 @@ SymbolInstance makeSymbolInstance(float x, float y, std::u16string key) {
ImageMap imageMap;
const ShapedTextOrientations shaping{};
style::SymbolLayoutProperties::Evaluated layout_;
IndexedSubfeature subfeature(0, "", "", 0);
IndexedSubfeature subfeature(0, {}, {}, 0);
Anchor anchor(x, y, 0, 0);
std::array<float, 2> textOffset{{0.0f, 0.0f}};
std::array<float, 2> iconOffset{{0.0f, 0.0f}};