diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2020-03-19 15:17:43 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-19 15:17:43 +0100 |
commit | b54b22e44a661f84882f581c5f82d248c4d54104 (patch) | |
tree | 14dd5bc24bf6178d6450327e18ae455515df57ca | |
parent | 13eb0fce976e4206ad9bfda75249ca309cc36e60 (diff) | |
parent | 0c3d8f089e46df6b6da9477991c79e4f4cc3502a (diff) |
Merge pull request #12619 from vespa-engine/balder/optimize-value-excutors
Balder/optimize value excutors.
23 files changed, 127 insertions, 80 deletions
diff --git a/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt b/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt index 8e1d18a87b7..a25d2abb477 100644 --- a/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt +++ b/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt @@ -1,6 +1,7 @@ # Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. vespa_add_library(eval_tensor_sparse OBJECT SOURCES + direct_sparse_tensor_builder.cpp sparse_tensor.cpp sparse_tensor_add.cpp sparse_tensor_address_builder.cpp diff --git a/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.cpp b/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.cpp new file mode 100644 index 00000000000..4a28b54d201 --- /dev/null +++ b/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.cpp @@ -0,0 +1,62 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "direct_sparse_tensor_builder.h" + +namespace vespalib::tensor { + +void +DirectSparseTensorBuilder::copyCells(const Cells &cells_in) +{ + for (const auto &cell : cells_in) { + SparseTensorAddressRef oldRef = cell.first; + SparseTensorAddressRef newRef(oldRef, _stash); + _cells[newRef] = cell.second; + } +} + +DirectSparseTensorBuilder::DirectSparseTensorBuilder() + : _stash(SparseTensor::STASH_CHUNK_SIZE), + _type(eval::ValueType::double_type()), + _cells() +{ +} + +DirectSparseTensorBuilder::DirectSparseTensorBuilder(const eval::ValueType &type_in) + : _stash(SparseTensor::STASH_CHUNK_SIZE), + _type(type_in), + _cells() +{ +} + +DirectSparseTensorBuilder::DirectSparseTensorBuilder(const eval::ValueType &type_in, const Cells &cells_in) + : _stash(SparseTensor::STASH_CHUNK_SIZE), + _type(type_in), + _cells() +{ + copyCells(cells_in); +} + +DirectSparseTensorBuilder::~DirectSparseTensorBuilder() = default; + +Tensor::UP +DirectSparseTensorBuilder::build() { + return std::make_unique<SparseTensor>(std::move(_type), std::move(_cells), std::move(_stash)); +} + +void +DirectSparseTensorBuilder::insertCell(SparseTensorAddressRef address, double value) { + // This address should not already exist and a new cell should be inserted. + insertCell(address, value, [](double, double) -> double { HDR_ABORT("should not be reached"); }); +} + +void +DirectSparseTensorBuilder::insertCell(SparseTensorAddressBuilder &address, double value) { + // This address should not already exist and a new cell should be inserted. + insertCell(address.getAddressRef(), value, [](double, double) -> double { HDR_ABORT("should not be reached"); }); +} + +void DirectSparseTensorBuilder::reserve(uint32_t estimatedCells) { + _cells.resize(estimatedCells*2); +} + +}
\ No newline at end of file diff --git a/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h b/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h index d54c8810a81..f9182a199be 100644 --- a/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h +++ b/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h @@ -25,43 +25,13 @@ private: Cells _cells; public: - void - copyCells(const Cells &cells_in) - { - for (const auto &cell : cells_in) { - SparseTensorAddressRef oldRef = cell.first; - SparseTensorAddressRef newRef(oldRef, _stash); - _cells[newRef] = cell.second; - } - } - - DirectSparseTensorBuilder() - : _stash(SparseTensor::STASH_CHUNK_SIZE), - _type(eval::ValueType::double_type()), - _cells() - { - } - - DirectSparseTensorBuilder(const eval::ValueType &type_in) - : _stash(SparseTensor::STASH_CHUNK_SIZE), - _type(type_in), - _cells() - { - } - - DirectSparseTensorBuilder(const eval::ValueType &type_in, const Cells &cells_in) - : _stash(SparseTensor::STASH_CHUNK_SIZE), - _type(type_in), - _cells() - { - copyCells(cells_in); - } + void copyCells(const Cells &cells_in); + DirectSparseTensorBuilder(); + DirectSparseTensorBuilder(const eval::ValueType &type_in); + DirectSparseTensorBuilder(const eval::ValueType &type_in, const Cells &cells_in); + ~DirectSparseTensorBuilder(); - ~DirectSparseTensorBuilder() {}; - - Tensor::UP build() { - return std::make_unique<SparseTensor>(std::move(_type), std::move(_cells), std::move(_stash)); - } + Tensor::UP build(); template <class Function> void insertCell(SparseTensorAddressRef address, double value, Function &&func) @@ -75,10 +45,7 @@ public: } } - void insertCell(SparseTensorAddressRef address, double value) { - // This address should not already exist and a new cell should be inserted. - insertCell(address, value, [](double, double) -> double { HDR_ABORT("should not be reached"); }); - } + void insertCell(SparseTensorAddressRef address, double value); template <class Function> void insertCell(SparseTensorAddressBuilder &address, double value, Function &&func) @@ -86,14 +53,11 @@ public: insertCell(address.getAddressRef(), value, func); } - void insertCell(SparseTensorAddressBuilder &address, double value) { - // This address should not already exist and a new cell should be inserted. - insertCell(address.getAddressRef(), value, [](double, double) -> double { HDR_ABORT("should not be reached"); }); - } + void insertCell(SparseTensorAddressBuilder &address, double value); eval::ValueType &fast_type() { return _type; } Cells &cells() { return _cells; } - void reserve(uint32_t estimatedCells) { _cells.resize(estimatedCells*2); } + void reserve(uint32_t estimatedCells); }; } diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp index 1fc93e8234f..d183c33f5cd 100644 --- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp @@ -245,5 +245,4 @@ SparseTensor::remove(const CellValues &cellAddresses) const } -VESPALIB_HASH_MAP_INSTANTIATE_H_E_M(vespalib::tensor::SparseTensorAddressRef, double, vespalib::hash<vespalib::tensor::SparseTensorAddressRef>, - std::equal_to<vespalib::tensor::SparseTensorAddressRef>, vespalib::hashtable_base::and_modulator); +VESPALIB_HASH_MAP_INSTANTIATE(vespalib::tensor::SparseTensorAddressRef, double); diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h index 880cd32c605..e5ea639b460 100644 --- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h @@ -22,7 +22,7 @@ class SparseTensor : public Tensor { public: using Cells = hash_map<SparseTensorAddressRef, double, hash<SparseTensorAddressRef>, - std::equal_to<SparseTensorAddressRef>, hashtable_base::and_modulator>; + std::equal_to<>, hashtable_base::and_modulator>; static constexpr size_t STASH_CHUNK_SIZE = 16384u; diff --git a/searchlib/src/vespa/searchlib/features/fieldlengthfeature.cpp b/searchlib/src/vespa/searchlib/features/fieldlengthfeature.cpp index 74bfa156b5f..0cbcf62de6b 100644 --- a/searchlib/src/vespa/searchlib/features/fieldlengthfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/fieldlengthfeature.cpp @@ -92,9 +92,7 @@ FeatureExecutor & FieldLengthBlueprint::createExecutor(const IQueryEnvironment &env, vespalib::Stash &stash) const { if (_field == 0) { - std::vector<feature_t> values; - values.push_back(fef::FieldPositionsIterator::UNKNOWN_LENGTH); - return stash.create<ValueExecutor>(values); + return stash.create<SingleValueExecutor>(fef::FieldPositionsIterator::UNKNOWN_LENGTH); } return stash.create<FieldLengthExecutor>(env, _field->id()); } diff --git a/searchlib/src/vespa/searchlib/features/matchcountfeature.cpp b/searchlib/src/vespa/searchlib/features/matchcountfeature.cpp index c061ace4854..f19e32793a1 100644 --- a/searchlib/src/vespa/searchlib/features/matchcountfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/matchcountfeature.cpp @@ -70,7 +70,7 @@ FeatureExecutor & MatchCountBlueprint::createExecutor(const IQueryEnvironment & queryEnv, vespalib::Stash &stash) const { if (_field == nullptr) { - return stash.create<ValueExecutor>(std::vector<feature_t>(1, 0.0)); + return stash.create<SingleZeroValueExecutor>(); } return stash.create<MatchCountExecutor>(_field->id(), queryEnv); } diff --git a/searchlib/src/vespa/searchlib/features/matchesfeature.cpp b/searchlib/src/vespa/searchlib/features/matchesfeature.cpp index a99c2330ee3..8d72978adf7 100644 --- a/searchlib/src/vespa/searchlib/features/matchesfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/matchesfeature.cpp @@ -81,7 +81,7 @@ FeatureExecutor & MatchesBlueprint::createExecutor(const IQueryEnvironment & queryEnv, vespalib::Stash &stash) const { if (_field == 0) { - return stash.create<ValueExecutor>(std::vector<feature_t>(1, 0.0)); + return stash.create<SingleZeroValueExecutor>(); } if (_termIdx != std::numeric_limits<uint32_t>::max()) { return stash.create<MatchesExecutor>(_field->id(), queryEnv, _termIdx, _termIdx + 1); diff --git a/searchlib/src/vespa/searchlib/features/nativeattributematchfeature.cpp b/searchlib/src/vespa/searchlib/features/nativeattributematchfeature.cpp index 865ea9fc3c4..ab8544634b5 100644 --- a/searchlib/src/vespa/searchlib/features/nativeattributematchfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/nativeattributematchfeature.cpp @@ -51,7 +51,7 @@ NativeAttributeMatchExecutor::createExecutor(const IQueryEnvironment & env, { Precomputed setup = preComputeSetup(env, params); if (setup.first.size() == 0) { - return stash.create<ValueExecutor>(std::vector<feature_t>(1, 0.0)); + return stash.create<SingleZeroValueExecutor>(); } else if (setup.first.size() == 1) { return stash.create<NativeAttributeMatchExecutorSingle>(setup); } else { diff --git a/searchlib/src/vespa/searchlib/features/nativefieldmatchfeature.cpp b/searchlib/src/vespa/searchlib/features/nativefieldmatchfeature.cpp index 2b6841750ad..2cdda669dd7 100644 --- a/searchlib/src/vespa/searchlib/features/nativefieldmatchfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/nativefieldmatchfeature.cpp @@ -173,7 +173,7 @@ NativeFieldMatchBlueprint::createExecutor(const IQueryEnvironment &env, vespalib { NativeFieldMatchExecutor &native = stash.create<NativeFieldMatchExecutor>(env, _params); if (native.empty()) { - return stash.create<ValueExecutor>(std::vector<feature_t>(1, 0.0)); + return stash.create<SingleZeroValueExecutor>(); } else { return native; } diff --git a/searchlib/src/vespa/searchlib/features/nativeproximityfeature.cpp b/searchlib/src/vespa/searchlib/features/nativeproximityfeature.cpp index 2809417e382..4da819b4dd3 100644 --- a/searchlib/src/vespa/searchlib/features/nativeproximityfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/nativeproximityfeature.cpp @@ -208,7 +208,7 @@ NativeProximityBlueprint::createExecutor(const IQueryEnvironment &env, vespalib: { NativeProximityExecutor &native = stash.create<NativeProximityExecutor>(env, _params); if (native.empty()) { - return stash.create<ValueExecutor>(std::vector<feature_t>(1, 0.0)); + return stash.create<SingleZeroValueExecutor>(); } else { return native; } diff --git a/searchlib/src/vespa/searchlib/features/nativerankfeature.cpp b/searchlib/src/vespa/searchlib/features/nativerankfeature.cpp index a980c265484..07f1dfb9d15 100644 --- a/searchlib/src/vespa/searchlib/features/nativerankfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/nativerankfeature.cpp @@ -157,7 +157,7 @@ NativeRankBlueprint::createExecutor(const IQueryEnvironment &, vespalib::Stash & if (_params.proximityWeight + _params.fieldMatchWeight + _params.attributeMatchWeight > 0) { return stash.create<NativeRankExecutor>(_params); } else { - return stash.create<ValueExecutor>(std::vector<feature_t>(1, 0.0)); + return stash.create<SingleZeroValueExecutor>(); } } diff --git a/searchlib/src/vespa/searchlib/features/queryfeature.cpp b/searchlib/src/vespa/searchlib/features/queryfeature.cpp index b927188c1aa..12cad613a80 100644 --- a/searchlib/src/vespa/searchlib/features/queryfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/queryfeature.cpp @@ -146,11 +146,10 @@ QueryBlueprint::createExecutor(const IQueryEnvironment &env, vespalib::Stash &st p = env.getProperties().lookup(_key2); } if (p.found()) { - values.push_back(asFeature(p.get())); + return stash.create<SingleValueExecutor>(asFeature(p.get())); } else { - values.push_back(_defaultValue); + return stash.create<SingleValueExecutor>(_defaultValue); } - return stash.create<ValueExecutor>(values); } } diff --git a/searchlib/src/vespa/searchlib/features/querytermcountfeature.cpp b/searchlib/src/vespa/searchlib/features/querytermcountfeature.cpp index cbaf9e97cb6..741501d3b6d 100644 --- a/searchlib/src/vespa/searchlib/features/querytermcountfeature.cpp +++ b/searchlib/src/vespa/searchlib/features/querytermcountfeature.cpp @@ -43,9 +43,7 @@ QueryTermCountBlueprint::setup(const IIndexEnvironment &, FeatureExecutor & QueryTermCountBlueprint::createExecutor(const IQueryEnvironment &env, vespalib::Stash &stash) const { - std::vector<feature_t> values; - values.push_back(static_cast<feature_t>(env.getNumTerms())); - return stash.create<ValueExecutor>(values); + return stash.create<SingleValueExecutor>(env.getNumTerms()); } } diff --git a/searchlib/src/vespa/searchlib/features/terminfofeature.cpp b/searchlib/src/vespa/searchlib/features/terminfofeature.cpp index ca7a5d8e248..b61021c4aa2 100644 --- a/searchlib/src/vespa/searchlib/features/terminfofeature.cpp +++ b/searchlib/src/vespa/searchlib/features/terminfofeature.cpp @@ -39,9 +39,7 @@ TermInfoBlueprint::createExecutor(const IQueryEnvironment &queryEnv, vespalib::S if (queryEnv.getNumTerms() > _termIdx) { queryIdx = _termIdx; } - std::vector<feature_t> values; - values.push_back(queryIdx); - return stash.create<ValueExecutor>(values); + return stash.create<SingleValueExecutor>(queryIdx); } } diff --git a/searchlib/src/vespa/searchlib/features/valuefeature.cpp b/searchlib/src/vespa/searchlib/features/valuefeature.cpp index 2b91cf1688b..64f2ba862e2 100644 --- a/searchlib/src/vespa/searchlib/features/valuefeature.cpp +++ b/searchlib/src/vespa/searchlib/features/valuefeature.cpp @@ -22,6 +22,12 @@ ValueExecutor::execute(uint32_t) } void +SingleValueExecutor::execute(uint32_t) +{ + outputs().set_number(0, _value); +} + +void SingleZeroValueExecutor::execute(uint32_t) { outputs().set_number(0, 0.0); @@ -56,10 +62,13 @@ ValueBlueprint::setup(const IIndexEnvironment &, const ParameterList & params) } FeatureExecutor & -ValueBlueprint::createExecutor(const IQueryEnvironment &queryEnv, vespalib::Stash &stash) const +ValueBlueprint::createExecutor(const IQueryEnvironment &, vespalib::Stash &stash) const { - (void) queryEnv; - return stash.create<ValueExecutor>(_values); + if (_values.size() == 1) { + return stash.create<SingleValueExecutor>(_values[0]); + } else { + return stash.create<ValueExecutor>(_values); + } } diff --git a/searchlib/src/vespa/searchlib/features/valuefeature.h b/searchlib/src/vespa/searchlib/features/valuefeature.h index 1cc6bd55bc1..d8e2ab70d0b 100644 --- a/searchlib/src/vespa/searchlib/features/valuefeature.h +++ b/searchlib/src/vespa/searchlib/features/valuefeature.h @@ -7,7 +7,7 @@ namespace search::features { -class ValueExecutor : public fef::FeatureExecutor +class ValueExecutor final : public fef::FeatureExecutor { private: std::vector<feature_t> _values; @@ -19,7 +19,18 @@ public: const std::vector<feature_t> & getValues() const { return _values; } }; -class SingleZeroValueExecutor : public fef::FeatureExecutor +class SingleValueExecutor final : public fef::FeatureExecutor +{ +private: + feature_t _value; + +public: + SingleValueExecutor(feature_t value) : _value(value) { } + bool isPure() override { return true; } + void execute(uint32_t docId) override; +}; + +class SingleZeroValueExecutor final : public fef::FeatureExecutor { public: SingleZeroValueExecutor() : FeatureExecutor() {} diff --git a/searchlib/src/vespa/searchlib/fef/properties.h b/searchlib/src/vespa/searchlib/fef/properties.h index 1cbc0ba9064..377926509bd 100644 --- a/searchlib/src/vespa/searchlib/fef/properties.h +++ b/searchlib/src/vespa/searchlib/fef/properties.h @@ -129,9 +129,10 @@ public: class Properties { private: - typedef vespalib::string Key; - typedef Property::Values Value; - typedef vespalib::hash_map<Key, Value> Map; + using Key = vespalib::string; + using Value = Property::Values; + using Map = vespalib::hash_map<Key, Value, vespalib::hash<Key>, + std::equal_to<>, vespalib::hashtable_base::and_modulator>; uint32_t _numValues; Map _data; diff --git a/searchlib/src/vespa/searchlib/fef/rank_program.cpp b/searchlib/src/vespa/searchlib/fef/rank_program.cpp index 48a9c7be147..0bc85a63ceb 100644 --- a/searchlib/src/vespa/searchlib/fef/rank_program.cpp +++ b/searchlib/src/vespa/searchlib/fef/rank_program.cpp @@ -3,6 +3,7 @@ #include "rank_program.h" #include "featureoverrider.h" #include <vespa/vespalib/locale/c.h> +#include <vespa/vespalib/stllike/hash_set.hpp> #include <algorithm> #include <cassert> @@ -14,7 +15,6 @@ using vespalib::Stash; namespace search::fef { using MappedValues = std::map<const NumberOrObject *, LazyValue>; -using ValueSet = std::set<const NumberOrObject *>; namespace { @@ -179,6 +179,7 @@ RankProgram::setup(const MatchData &md, const auto &specs = _resolver->getExecutorSpecs(); _executors.reserve(specs.size()); + _is_const.resize(specs.size()*2); // Reserve space in hashmap for executors to be const for (uint32_t i = 0; i < specs.size(); ++i) { vespalib::ArrayRef<NumberOrObject> outputs = _hot_stash.create_array<NumberOrObject>(specs[i].output_types.size()); StashSelector stash(_hot_stash, _cold_stash); diff --git a/searchlib/src/vespa/searchlib/fef/rank_program.h b/searchlib/src/vespa/searchlib/fef/rank_program.h index aa6f77abce4..15b7912bfb1 100644 --- a/searchlib/src/vespa/searchlib/fef/rank_program.h +++ b/searchlib/src/vespa/searchlib/fef/rank_program.h @@ -10,7 +10,7 @@ #include <vespa/vespalib/stllike/string.h> #include <vespa/vespalib/util/array.h> #include <vespa/vespalib/util/stash.h> -#include <set> +#include <vespa/vespalib/stllike/hash_set.h> namespace search::fef { @@ -31,7 +31,8 @@ private: RankProgram &operator=(const RankProgram &) = delete; using MappedValues = std::map<const NumberOrObject *, LazyValue>; - using ValueSet = std::set<const NumberOrObject *>; + using ValueSet = vespalib::hash_set<const NumberOrObject *, vespalib::hash<const NumberOrObject *>, + std::equal_to<>, vespalib::hashtable_base::and_modulator>; BlueprintResolver::SP _resolver; vespalib::Stash _hot_stash; diff --git a/vespalib/src/tests/stllike/hash_test.cpp b/vespalib/src/tests/stllike/hash_test.cpp index 017a16ee7b6..b39b6859623 100644 --- a/vespalib/src/tests/stllike/hash_test.cpp +++ b/vespalib/src/tests/stllike/hash_test.cpp @@ -356,6 +356,9 @@ TEST("test hash set find") EXPECT_TRUE(*set.find(S(1)) == S(1)); auto cit = set.find<uint32_t>(7); EXPECT_TRUE(*cit == S(7)); + + EXPECT_EQUAL(1u, set.count(S(7))); + EXPECT_EQUAL(0u, set.count(S(10007))); } TEST("test hash set range constructor") diff --git a/vespalib/src/vespa/vespalib/stllike/hash_map.hpp b/vespalib/src/vespa/vespalib/stllike/hash_map.hpp index 08edcf3c837..61789f6e2be 100644 --- a/vespalib/src/vespa/vespalib/stllike/hash_map.hpp +++ b/vespalib/src/vespa/vespalib/stllike/hash_map.hpp @@ -73,11 +73,12 @@ hash_map<K, V, H, EQ, M>::getMemoryUsed() const template vespalib::hashtable<K, std::pair<K,V>, H, E, vespalib::Select1st<std::pair<K,V>>, M>::insert_result \ vespalib::hashtable<K, std::pair<K,V>, H, E, vespalib::Select1st<std::pair<K,V>>, M>::insert(std::pair<K,V> &&); \ template vespalib::hashtable<K, std::pair<K,V>, H, E, vespalib::Select1st<std::pair<K,V>>, M>::insert_result \ - vespalib::hashtable<K, std::pair<K,V>, H, E, vespalib::Select1st<std::pair<K,V>>, M>::insertInternal(std::pair<K,V> &&); \ - template class vespalib::Array<vespalib::hash_node<std::pair<K,V>>>; + vespalib::hashtable<K, std::pair<K,V>, H, E, vespalib::Select1st<std::pair<K,V>>, M>::insertInternal(std::pair<K,V> &&); #define VESPALIB_HASH_MAP_INSTANTIATE_H_E(K, V, H, E) \ - VESPALIB_HASH_MAP_INSTANTIATE_H_E_M(K, V, H, E, vespalib::hashtable_base::prime_modulator) + template class vespalib::Array<vespalib::hash_node<std::pair<K,V>>>; \ + VESPALIB_HASH_MAP_INSTANTIATE_H_E_M(K, V, H, E, vespalib::hashtable_base::prime_modulator) \ + VESPALIB_HASH_MAP_INSTANTIATE_H_E_M(K, V, H, E, vespalib::hashtable_base::and_modulator) #define VESPALIB_HASH_MAP_INSTANTIATE_H(K, V, H) VESPALIB_HASH_MAP_INSTANTIATE_H_E(K, V, H, std::equal_to<>) diff --git a/vespalib/src/vespa/vespalib/stllike/hash_set.h b/vespalib/src/vespa/vespalib/stllike/hash_set.h index 8d315ebfd07..08288086bf3 100644 --- a/vespalib/src/vespa/vespalib/stllike/hash_set.h +++ b/vespalib/src/vespa/vespalib/stllike/hash_set.h @@ -42,6 +42,7 @@ public: template<typename InputIt> void insert(InputIt first, InputIt last); void erase(const K & key); + size_t count(const K & key) const { return _ht.find(key) != end() ? 1 : 0; } iterator find(const K & key) { return _ht.find(key); } const_iterator find(const K & key) const { return _ht.find(key); } |