Use an HashMap to store options in option manager
Turns out looking for options can get pretty slow, so O(1) lookup seems better. This should improve the performance of the #1460 issue
This commit is contained in:
parent
fb22349249
commit
7ceb768a2e
|
@ -48,13 +48,13 @@ struct option_not_found : public runtime_error
|
|||
|
||||
Option& OptionManager::get_local_option(StringView name)
|
||||
{
|
||||
auto it = find_option(m_options, name);
|
||||
auto it = m_options.find(name);
|
||||
if (it != m_options.end())
|
||||
return **it;
|
||||
return *(it->value);
|
||||
else if (m_parent)
|
||||
{
|
||||
m_options.emplace_back((*m_parent)[name].clone(*this));
|
||||
return *m_options.back();
|
||||
auto* clone = (*m_parent)[name].clone(*this);
|
||||
return *m_options.insert({clone->name(), std::unique_ptr<Option>{clone}});
|
||||
}
|
||||
else
|
||||
throw option_not_found(name);
|
||||
|
@ -63,9 +63,9 @@ Option& OptionManager::get_local_option(StringView name)
|
|||
|
||||
Option& OptionManager::operator[](StringView name)
|
||||
{
|
||||
auto it = find_option(m_options, name);
|
||||
auto it = m_options.find(name);
|
||||
if (it != m_options.end())
|
||||
return **it;
|
||||
return *it->value;
|
||||
else if (m_parent)
|
||||
return (*m_parent)[name];
|
||||
else
|
||||
|
@ -80,10 +80,9 @@ const Option& OptionManager::operator[](StringView name) const
|
|||
void OptionManager::unset_option(StringView name)
|
||||
{
|
||||
kak_assert(m_parent); // cannot unset option on global manager
|
||||
auto it = find_option(m_options, name);
|
||||
if (it != m_options.end())
|
||||
if (m_options.contains(name))
|
||||
{
|
||||
m_options.erase(it);
|
||||
m_options.erase(name);
|
||||
on_option_changed((*m_parent)[name]);
|
||||
}
|
||||
}
|
||||
|
@ -93,11 +92,11 @@ OptionManager::OptionList OptionManager::flatten_options() const
|
|||
OptionList res = m_parent ? m_parent->flatten_options() : OptionList{};
|
||||
for (auto& option : m_options)
|
||||
{
|
||||
auto it = find_option(res, option->name());
|
||||
auto it = find_if(res, [&](const Option* opt) { return opt->name() == option.key; });
|
||||
if (it != res.end())
|
||||
*it = option.get();
|
||||
*it = option.value.get();
|
||||
else
|
||||
res.emplace_back(option.get());
|
||||
res.emplace_back(option.value.get());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -105,8 +104,7 @@ OptionManager::OptionList OptionManager::flatten_options() const
|
|||
void OptionManager::on_option_changed(const Option& option)
|
||||
{
|
||||
// if parent option changed, but we overrided it, it's like nothing happened
|
||||
if (&option.manager() != this and
|
||||
find_option(m_options, option.name()) != m_options.end())
|
||||
if (&option.manager() != this and m_options.contains(option.name()))
|
||||
return;
|
||||
|
||||
// The watcher list might get mutated during calls to on_option_changed
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "exception.hh"
|
||||
#include "option.hh"
|
||||
#include "vector.hh"
|
||||
#include "hash_map.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
@ -101,7 +103,7 @@ private:
|
|||
friend class Scope;
|
||||
friend class OptionsRegistry;
|
||||
|
||||
Vector<std::unique_ptr<Option>, MemoryDomain::Options> m_options;
|
||||
HashMap<StringView, std::unique_ptr<Option>, MemoryDomain::Options> m_options;
|
||||
OptionManager* m_parent;
|
||||
|
||||
mutable Vector<OptionManagerWatcher*, MemoryDomain::Options> m_watchers;
|
||||
|
@ -190,13 +192,6 @@ template<typename T> bool Option::is_of_type() const
|
|||
return dynamic_cast<const TypedOption<T>*>(this) != nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto find_option(T& container, StringView name) -> decltype(container.begin())
|
||||
{
|
||||
using ptr_type = decltype(*container.begin());
|
||||
return find_if(container, [&name](const ptr_type& opt) { return opt->name() == name; });
|
||||
}
|
||||
|
||||
class OptionsRegistry
|
||||
{
|
||||
public:
|
||||
|
@ -217,18 +212,18 @@ public:
|
|||
throw runtime_error{format("name '{}' contains char out of [a-zA-Z0-9_]", name)};
|
||||
|
||||
auto& opts = m_global_manager.m_options;
|
||||
auto it = find_option(opts, name);
|
||||
auto it = opts.find(name);
|
||||
if (it != opts.end())
|
||||
{
|
||||
if ((*it)->is_of_type<T>() and (*it)->flags() == flags)
|
||||
return **it;
|
||||
if (it->value->is_of_type<T>() and it->value->flags() == flags)
|
||||
return *it->value;
|
||||
throw runtime_error{format("option '{}' already declared with different type or flags", name)};
|
||||
}
|
||||
String doc = docstring.empty() ? format("[{}]", option_type_name(Meta::Type<T>{}))
|
||||
: format("[{}] - {}", option_type_name(Meta::Type<T>{}), docstring);
|
||||
m_descs.emplace_back(new OptionDesc{name.str(), std::move(doc), flags});
|
||||
opts.emplace_back(new TypedCheckedOption<T, validator>{m_global_manager, *m_descs.back(), value});
|
||||
return *opts.back();
|
||||
return *opts.insert({m_descs.back()->name(),
|
||||
make_unique<TypedCheckedOption<T, validator>>(m_global_manager, *m_descs.back(), value)});
|
||||
}
|
||||
|
||||
const OptionDesc* option_desc(StringView name) const
|
||||
|
|
|
@ -257,6 +257,7 @@ private:
|
|||
static_assert(std::is_trivial<StringView>::value, "");
|
||||
|
||||
template<> struct HashCompatible<String, StringView> : std::true_type {};
|
||||
template<> struct HashCompatible<StringView, String> : std::true_type {};
|
||||
|
||||
inline String::String(StringView str) : String{str.begin(), str.length()} {}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user