From 34f0461a68b3a55399b69f7f7392c64a3ff3735a Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Wed, 14 Aug 2024 21:40:13 +0800 Subject: [PATCH 01/25] feat udpate config to configuration --- CMakeLists.txt | 6 +- .../config/{config.cc => configuration.cc} | 33 ++--- .../base/config/{config.h => configuration.h} | 20 +-- ...le_config.cc => ini_file_configuration.cc} | 28 ++-- ...file_config.h => ini_file_configuration.h} | 10 +- ...test.cc => ini_file_configuration_test.cc} | 11 +- tile/base/config/layered_config.cc | 129 ----------------- tile/base/config/layered_config.h | 57 -------- tile/base/config/layered_configuration.cc | 133 ++++++++++++++++++ tile/base/config/layered_configuration.h | 57 ++++++++ tile/base/configuration.h | 11 ++ tile/tile.h | 6 +- 12 files changed, 258 insertions(+), 243 deletions(-) rename tile/base/config/{config.cc => configuration.cc} (75%) rename tile/base/config/{config.h => configuration.h} (89%) rename tile/base/config/{ini_file_config.cc => ini_file_configuration.cc} (77%) rename tile/base/config/{ini_file_config.h => ini_file_configuration.h} (81%) rename tile/base/config/{ini_file_config_test.cc => ini_file_configuration_test.cc} (72%) delete mode 100644 tile/base/config/layered_config.cc delete mode 100644 tile/base/config/layered_config.h create mode 100644 tile/base/config/layered_configuration.cc create mode 100644 tile/base/config/layered_configuration.h create mode 100644 tile/base/configuration.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7631cc6..bbf65c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,9 +207,9 @@ set(TILE_SRCS "tile/rpc/protocol/http/buffer_io.cc" "tile/rpc/protocol/message.cc" # "tile/rpc/server.cc" - "tile/base/config/config.cc" - "tile/base/config/ini_file_config.cc" - "tile/base/config/layered_config.cc" + "tile/base/config/configuration.cc" + "tile/base/config/ini_file_configuration.cc" + "tile/base/config/layered_configuration.cc" ) if((NOT TILE_HAVE_GETIFADDRS) OR (NOT TILE_HAVE_FREEIFADDRS)) diff --git a/tile/base/config/config.cc b/tile/base/config/configuration.cc similarity index 75% rename from tile/base/config/config.cc rename to tile/base/config/configuration.cc index e56cf21..482a93b 100644 --- a/tile/base/config/config.cc +++ b/tile/base/config/configuration.cc @@ -1,26 +1,26 @@ -#include "tile/base/config/config.h" +#include "tile/base/config/configuration.h" #include "tile/base/thread/unique_lock.h" namespace tile { namespace util { -bool Config::Has(const Slice &key) const { +bool Configuration::Has(const Slice &key) const { UniqueLock lock(mutex_); std::string value; return GetRaw(key, &value); } -void Config::Remove(const Slice &key) {} +void Configuration::Remove(const Slice &key) {} -void Config::EnableEvents(bool enable) { events_enabled_ = enable; } -bool Config::EventsEnabled() const { return events_enabled_; } +void Configuration::EnableEvents(bool enable) { events_enabled_ = enable; } +bool Configuration::EventsEnabled() const { return events_enabled_; } -Config::Keys Config::keys(const Slice &root) const { +Configuration::Keys Configuration::keys(const Slice &root) const { UniqueLock lock(mutex_); return Enumerate(root); } #define TILE_DEFINE_CONFIG_GETTER(type, name) \ - std::optional Config::Get##name(const Slice &key) const { \ + std::optional Configuration::Get##name(const Slice &key) const { \ std::string value; \ if (GetRaw(key, &value)) { \ auto opt = TryParseTraits::TryParse(value); \ @@ -33,7 +33,7 @@ Config::Keys Config::keys(const Slice &root) const { return std::nullopt; \ } \ } \ - type Config::Get##name(const Slice &key, type default_value) const { \ + type Configuration::Get##name(const Slice &key, type default_value) const { \ auto opt = Get##name(key); \ if (opt.has_value()) { \ return *opt; \ @@ -43,11 +43,11 @@ Config::Keys Config::keys(const Slice &root) const { } #define TILE_DEFINE_CONFIG_SETTER(type, name) \ - void Config::Set##name(const Slice &key, type value) { \ + void Configuration::Set##name(const Slice &key, type value) { \ SetRawWithEvent(key, Format("{}", value)); \ } -std::optional Config::GetString(const Slice &key) const { +std::optional Configuration::GetString(const Slice &key) const { std::string value; UniqueLock lock(mutex_); if (GetRaw(key, &value)) { @@ -57,16 +57,16 @@ std::optional Config::GetString(const Slice &key) const { } } -std::string Config::GetString(const Slice &key, - std::string default_value) const { +std::string Configuration::GetString(const Slice &key, + std::string default_value) const { auto opt = GetString(key); return opt.has_value() ? *opt : default_value; } -void Config::SetString(const Slice &key, const std::string &value) { +void Configuration::SetString(const Slice &key, const std::string &value) { SetRawWithEvent(key, value); } -void Config::SetBool(const Slice &key, bool value) { +void Configuration::SetBool(const Slice &key, bool value) { SetRawWithEvent(key, value ? "true" : "false"); } @@ -91,7 +91,8 @@ TILE_DEFINE_CONFIG_SETTER(uint32_t, UInt32) TILE_DEFINE_CONFIG_SETTER(uint64_t, UInt64) TILE_DEFINE_CONFIG_SETTER(double, Double) -void Config::SetRawWithEvent(const Slice &key, const std::string &value) { +void Configuration::SetRawWithEvent(const Slice &key, + const std::string &value) { if (events_enabled_) { OnChanging(key, value); } @@ -106,7 +107,7 @@ void Config::SetRawWithEvent(const Slice &key, const std::string &value) { } } -Config::~Config() {} +Configuration::~Configuration() {} } // namespace util diff --git a/tile/base/config/config.h b/tile/base/config/configuration.h similarity index 89% rename from tile/base/config/config.h rename to tile/base/config/configuration.h index 32e3204..2365340 100644 --- a/tile/base/config/config.h +++ b/tile/base/config/configuration.h @@ -1,5 +1,5 @@ -#ifndef TILE_BASE_CONFIG_CONFIG_H -#define TILE_BASE_CONFIG_CONFIG_H +#ifndef TILE_BASE_CONFIG_CONFIGURATION_H +#define TILE_BASE_CONFIG_CONFIGURATION_H #pragma once #include "tile/base/optional.h" @@ -12,10 +12,10 @@ namespace tile { namespace util { -class Config : public RefCounted { +class Configuration : public RefCounted { public: using Keys = std::vector; - using Ptr = RefPtr; + using Ptr = RefPtr; // events // Key, Value @@ -98,13 +98,13 @@ protected: protected: class ScopedLock { public: - explicit ScopedLock(const Config &config) : config_(config) { + explicit ScopedLock(const Configuration &config) : config_(config) { config_.mutex_.Lock(); } ~ScopedLock() { config_.mutex_.Unlock(); } private: - const Config &config_; + const Configuration &config_; }; virtual bool GetRaw(const Slice &key, std::string *value) const = 0; @@ -112,10 +112,10 @@ protected: virtual void RemoveRaw(const Slice &key) = 0; virtual Keys Enumerate(const Slice &range) const = 0; void SetRawWithEvent(const Slice &key, const std::string &value); - virtual ~Config(); + virtual ~Configuration(); - friend class std::default_delete; - friend class LayeredConfig; + friend class std::default_delete; + friend class LayeredConfiguration; private: mutable Mutex mutex_; @@ -124,4 +124,4 @@ private: } // namespace util } // namespace tile -#endif // TILE_BASE_CONFIG_CONFIG_H +#endif // TILE_BASE_CONFIG_CONFIGURATION_H diff --git a/tile/base/config/ini_file_config.cc b/tile/base/config/ini_file_configuration.cc similarity index 77% rename from tile/base/config/ini_file_config.cc rename to tile/base/config/ini_file_configuration.cc index c3838c5..cb2c9bc 100644 --- a/tile/base/config/ini_file_config.cc +++ b/tile/base/config/ini_file_configuration.cc @@ -1,16 +1,16 @@ -#include "tile/base/config/ini_file_config.h" +#include "tile/base/config/ini_file_configuration.h" #include "tile/base/thread/scoped_lock.h" namespace tile { namespace util { -IniFileConfig::IniFileConfig() {} +IniFileConfiguration::IniFileConfiguration() {} // IniFileConfig::IniFileConfig(std::istream &istr) { load(istr); } // IniFileConfig::IniFileConfig(const std::string &path) { load(path); } -IniFileConfig::~IniFileConfig() {} +IniFileConfiguration::~IniFileConfiguration() {} -bool IniFileConfig::load(std::istream &istr) { - Config::ScopedLock lock(*this); +bool IniFileConfiguration::load(std::istream &istr) { + Configuration::ScopedLock lock(*this); map_.clear(); section_key_.clear(); while (!istr.eof()) { @@ -18,7 +18,7 @@ bool IniFileConfig::load(std::istream &istr) { } return true; } -bool IniFileConfig::load(const std::string &path) { +bool IniFileConfiguration::load(const std::string &path) { std::ifstream istr(path); if (istr.good()) { return load(istr); @@ -26,7 +26,7 @@ bool IniFileConfig::load(const std::string &path) { return false; } } -bool IniFileConfig::GetRaw(const Slice &key, std::string *value) const { +bool IniFileConfiguration::GetRaw(const Slice &key, std::string *value) const { auto iter = map_.find(key.ToString()); if (iter != map_.end()) { *value = iter->second; @@ -35,12 +35,12 @@ bool IniFileConfig::GetRaw(const Slice &key, std::string *value) const { return false; } } -bool IniFileConfig::SetRaw(const Slice &key, const Slice &value) { +bool IniFileConfiguration::SetRaw(const Slice &key, const Slice &value) { map_[key] = value; return true; } -void IniFileConfig::RemoveRaw(const Slice &key) { +void IniFileConfiguration::RemoveRaw(const Slice &key) { std::string prefix = key; if (!prefix.empty()) { prefix.push_back('.'); @@ -57,8 +57,8 @@ void IniFileConfig::RemoveRaw(const Slice &key) { } } -Config::Keys IniFileConfig::Enumerate(const Slice &key) const { - Config::Keys range; +Configuration::Keys IniFileConfiguration::Enumerate(const Slice &key) const { + Configuration::Keys range; std::set keys; std::string prefix = key.ToString(); if (prefix.empty()) { @@ -86,7 +86,7 @@ Config::Keys IniFileConfig::Enumerate(const Slice &key) const { return range; } -void IniFileConfig::ParseLine(std::istream &istr) { +void IniFileConfiguration::ParseLine(std::istream &istr) { static const int eof = std::char_traits::eof(); auto ReadLine = [&](std::string *line) { line->clear(); @@ -135,8 +135,8 @@ void IniFileConfig::ParseLine(std::istream &istr) { } } } -bool IniFileConfig::ICompare::operator()(const std::string &s1, - const std::string &s2) const { +bool IniFileConfiguration::ICompare::operator()(const std::string &s1, + const std::string &s2) const { auto len = std::min(s1.size(), s2.size()); return strncmp(s1.c_str(), s2.c_str(), len) < 0; } diff --git a/tile/base/config/ini_file_config.h b/tile/base/config/ini_file_configuration.h similarity index 81% rename from tile/base/config/ini_file_config.h rename to tile/base/config/ini_file_configuration.h index fe3e1a9..f9a1b08 100644 --- a/tile/base/config/ini_file_config.h +++ b/tile/base/config/ini_file_configuration.h @@ -3,17 +3,17 @@ #pragma once -#include "tile/base/config/config.h" +#include "tile/base/config/configuration.h" #include namespace tile { namespace util { -class IniFileConfig : public Config { +class IniFileConfiguration : public Configuration { public: - using Ptr = RefPtr; + using Ptr = RefPtr; - IniFileConfig(); - ~IniFileConfig() override; + IniFileConfiguration(); + ~IniFileConfiguration() override; // IniFileConfig(std::istream &istr); // IniFileConfig(const std::string &path); bool load(std::istream &istr); diff --git a/tile/base/config/ini_file_config_test.cc b/tile/base/config/ini_file_configuration_test.cc similarity index 72% rename from tile/base/config/ini_file_config_test.cc rename to tile/base/config/ini_file_configuration_test.cc index e110933..ffd1de2 100644 --- a/tile/base/config/ini_file_config_test.cc +++ b/tile/base/config/ini_file_configuration_test.cc @@ -1,4 +1,4 @@ -#include "tile/base/config/ini_file_config.h" +#include "tile/base/config/ini_file_configuration.h" #include "gtest/gtest.h" const char *kIniFileConfig = R"( @@ -18,16 +18,17 @@ a=4 namespace tile { namespace util { -static_assert(!detail::HasClassofImpl::value, ""); +static_assert( + !detail::HasClassofImpl::value, ""); TEST(IniFileConfig, LoadFromIStream) { std::stringstream ss(kIniFileConfig); - Config::Ptr config = MakeRefCounted(); + Configuration::Ptr config = MakeRefCounted(); ASSERT_FALSE(config->Has("a")); ASSERT_FALSE(config->Has("sec1.a")); ASSERT_FALSE(config->Has("sec3.a")); - if (config.Is()) { - IniFileConfig::Ptr ini = config.As(); + if (config.Is()) { + IniFileConfiguration::Ptr ini = config.As(); ASSERT_TRUE(ini->load(ss)); } ASSERT_TRUE(config->Has("a")); diff --git a/tile/base/config/layered_config.cc b/tile/base/config/layered_config.cc deleted file mode 100644 index 3b90173..0000000 --- a/tile/base/config/layered_config.cc +++ /dev/null @@ -1,129 +0,0 @@ -#include "tile/base/config/layered_config.h" - -namespace tile { -namespace util { - -LayeredConfig::LayeredConfig() {} -LayeredConfig::~LayeredConfig() {} - -void LayeredConfig::Add(Config::Ptr cfg) { Add(cfg, highest(), false); } - -void LayeredConfig::Add(Config::Ptr cfg, int priority) { - Add(cfg, priority, false); -} - -void LayeredConfig::Add(Config::Ptr cfg, const std::string &label) { - Add(cfg, label, highest(), false); -} - -void LayeredConfig::Add(Config::Ptr cfg, const std::string &label, - int priority) { - Add(cfg, label, priority, false); -} - -void LayeredConfig::Add(Config::Ptr cfg, const std::string &label, - bool writeable) { - Add(cfg, label, highest(), writeable); -} - -void LayeredConfig::Add(Config::Ptr cfg, const std::string &label, int priority, - bool writeable) { - Config::ScopedLock lock(*this); - ConfigItem item; - item.cfg = cfg; - item.priority = priority; - item.writeable = writeable; - item.label = label; - auto it = configs_.begin(); - while (it != configs_.end() && it->priority < priority) { - ++it; - } - configs_.insert(it, item); -} - -void LayeredConfig::Add(Config::Ptr cfg, int priority, bool writeable) { - Add(cfg, std::string(), priority, writeable); -} -void LayeredConfig::AddWriteable(Config::Ptr cfg, int priority) { - Add(cfg, priority, true); -} - -Config::Ptr LayeredConfig::Find(const Slice &label) const { - Config::ScopedLock lock(*this); - - for (const auto &conf : configs_) { - if (conf.label == label) { - return conf.cfg; - } - } - return 0; -} - -void LayeredConfig::RemoveConfig(Config::Ptr cfg) { - Config::ScopedLock lock(*this); - for (auto it = configs_.begin(); it != configs_.end();) { - if (it->cfg == cfg) { - it = configs_.erase(it); - } else { - ++it; - } - } -} - -bool LayeredConfig::GetRaw(const Slice &key, std::string *value) const { - for (const auto &conf : configs_) { - if (conf.cfg->GetRaw(key, value)) { - return true; - } - } - return false; -} - -bool LayeredConfig::SetRaw(const Slice &key, const Slice &value) { - for (const auto &conf : configs_) { - if (conf.writeable && conf.cfg->SetRaw(key, value)) { - return true; - } - } - return false; -} - -Config::Keys LayeredConfig::Enumerate(const Slice &key) const { - Config::Keys keys; - std::set key_set; - for (const auto &conf : configs_) { - auto conf_keys = conf.cfg->Enumerate(key); - for (const auto &k : conf_keys) { - if (key_set.insert(k).second) { - keys.push_back(k); - } - } - } - return keys; -} - -void LayeredConfig::RemoveRaw(const std::string &key) { - for (auto &conf : configs_) { - if (conf.writeable) { - conf.cfg->RemoveRaw(key); - } - } -} - -int LayeredConfig::lowest() const { - if (configs_.empty()) { - return 0; - } else { - return configs_.front().priority - 1; - } -} -int LayeredConfig::highest() const { - if (configs_.empty()) { - return 0; - } else { - return configs_.back().priority + 1; - } -} - -} // namespace util -} // namespace tile diff --git a/tile/base/config/layered_config.h b/tile/base/config/layered_config.h deleted file mode 100644 index e481515..0000000 --- a/tile/base/config/layered_config.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef TILE_BASE_CONFIG_LAYERED_CONFIG_H -#define TILE_BASE_CONFIG_LAYERED_CONFIG_H - -#pragma once - -#include "tile/base/config/config.h" -#include - -namespace tile { -namespace util { -class LayeredConfig : public Config { -public: - using Ptr = RefPtr; - LayeredConfig(); - LayeredConfig(const LayeredConfig &) = delete; - LayeredConfig &operator=(const LayeredConfig &) = delete; - - void Add(Config::Ptr cfg); - void Add(Config::Ptr cfg, int priority); - void Add(Config::Ptr cfg, const std::string &label); - void Add(Config::Ptr cfg, const std::string &label, int priority); - void Add(Config::Ptr cfg, const std::string &label, bool writeable); - void Add(Config::Ptr cfg, const std::string &label, int priority, - bool writeable); - void Add(Config::Ptr cfg, int priority, bool writeable); - void AddWriteable(Config::Ptr cfg, int priority); - Config::Ptr Find(const Slice &label) const; - void RemoveConfig(Config::Ptr cfg); - -protected: - struct ConfigItem { - Config::Ptr cfg; - // ... > -2 > -1 > 0 > 1 > 2 > 3 > 4 ... - int priority; - // can remove or set new? - bool writeable; - std::string label; - }; - - bool GetRaw(const Slice &key, std::string *value) const override; - bool SetRaw(const Slice &key, const Slice &value) override; - Config::Keys Enumerate(const Slice &key) const override; - void RemoveRaw(const std::string &key); - - int lowest() const; - int highest() const; - - ~LayeredConfig(); - -private: - using ConfigList = std::list; - ConfigList configs_; -}; -} // namespace util -} // namespace tile - -#endif // TILE_BASE_CONFIG_LAYERED_CONFIG_H diff --git a/tile/base/config/layered_configuration.cc b/tile/base/config/layered_configuration.cc new file mode 100644 index 0000000..80910ed --- /dev/null +++ b/tile/base/config/layered_configuration.cc @@ -0,0 +1,133 @@ +#include "tile/base/config/layered_configuration.h" + +namespace tile { +namespace util { + +LayeredConfiguration::LayeredConfiguration() {} +LayeredConfiguration::~LayeredConfiguration() {} + +void LayeredConfiguration::Add(Configuration::Ptr cfg) { + Add(cfg, highest(), false); +} + +void LayeredConfiguration::Add(Configuration::Ptr cfg, int priority) { + Add(cfg, priority, false); +} + +void LayeredConfiguration::Add(Configuration::Ptr cfg, + const std::string &label) { + Add(cfg, label, highest(), false); +} + +void LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, + int priority) { + Add(cfg, label, priority, false); +} + +void LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, + bool writeable) { + Add(cfg, label, highest(), writeable); +} + +void LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, + int priority, bool writeable) { + Configuration::ScopedLock lock(*this); + ConfigItem item; + item.cfg = cfg; + item.priority = priority; + item.writeable = writeable; + item.label = label; + auto it = configs_.begin(); + while (it != configs_.end() && it->priority < priority) { + ++it; + } + configs_.insert(it, item); +} + +void LayeredConfiguration::Add(Configuration::Ptr cfg, int priority, + bool writeable) { + Add(cfg, std::string(), priority, writeable); +} +void LayeredConfiguration::AddWriteable(Configuration::Ptr cfg, int priority) { + Add(cfg, priority, true); +} + +Configuration::Ptr LayeredConfiguration::Find(const Slice &label) const { + Configuration::ScopedLock lock(*this); + + for (const auto &conf : configs_) { + if (conf.label == label) { + return conf.cfg; + } + } + return 0; +} + +void LayeredConfiguration::RemoveConfig(Configuration::Ptr cfg) { + Configuration::ScopedLock lock(*this); + for (auto it = configs_.begin(); it != configs_.end();) { + if (it->cfg == cfg) { + it = configs_.erase(it); + } else { + ++it; + } + } +} + +bool LayeredConfiguration::GetRaw(const Slice &key, std::string *value) const { + for (const auto &conf : configs_) { + if (conf.cfg->GetRaw(key, value)) { + return true; + } + } + return false; +} + +bool LayeredConfiguration::SetRaw(const Slice &key, const Slice &value) { + for (const auto &conf : configs_) { + if (conf.writeable && conf.cfg->SetRaw(key, value)) { + return true; + } + } + return false; +} + +Configuration::Keys LayeredConfiguration::Enumerate(const Slice &key) const { + Configuration::Keys keys; + std::set key_set; + for (const auto &conf : configs_) { + auto conf_keys = conf.cfg->Enumerate(key); + for (const auto &k : conf_keys) { + if (key_set.insert(k).second) { + keys.push_back(k); + } + } + } + return keys; +} + +void LayeredConfiguration::RemoveRaw(const std::string &key) { + for (auto &conf : configs_) { + if (conf.writeable) { + conf.cfg->RemoveRaw(key); + } + } +} + +int LayeredConfiguration::lowest() const { + if (configs_.empty()) { + return 0; + } else { + return configs_.front().priority - 1; + } +} +int LayeredConfiguration::highest() const { + if (configs_.empty()) { + return 0; + } else { + return configs_.back().priority + 1; + } +} + +} // namespace util +} // namespace tile diff --git a/tile/base/config/layered_configuration.h b/tile/base/config/layered_configuration.h new file mode 100644 index 0000000..db498ff --- /dev/null +++ b/tile/base/config/layered_configuration.h @@ -0,0 +1,57 @@ +#ifndef TILE_BASE_CONFIG_LAYERED_CONFIGURATION_H +#define TILE_BASE_CONFIG_LAYERED_CONFIGURATION_H + +#pragma once + +#include "tile/base/config/configuration.h" +#include + +namespace tile { +namespace util { +class LayeredConfiguration : public Configuration { +public: + using Ptr = RefPtr; + LayeredConfiguration(); + LayeredConfiguration(const LayeredConfiguration &) = delete; + LayeredConfiguration &operator=(const LayeredConfiguration &) = delete; + + void Add(Configuration::Ptr cfg); + void Add(Configuration::Ptr cfg, int priority); + void Add(Configuration::Ptr cfg, const std::string &label); + void Add(Configuration::Ptr cfg, const std::string &label, int priority); + void Add(Configuration::Ptr cfg, const std::string &label, bool writeable); + void Add(Configuration::Ptr cfg, const std::string &label, int priority, + bool writeable); + void Add(Configuration::Ptr cfg, int priority, bool writeable); + void AddWriteable(Configuration::Ptr cfg, int priority); + Configuration::Ptr Find(const Slice &label) const; + void RemoveConfig(Configuration::Ptr cfg); + +protected: + struct ConfigItem { + Configuration::Ptr cfg; + // ... > -2 > -1 > 0 > 1 > 2 > 3 > 4 ... + int priority; + // can remove or set new? + bool writeable; + std::string label; + }; + + bool GetRaw(const Slice &key, std::string *value) const override; + bool SetRaw(const Slice &key, const Slice &value) override; + Configuration::Keys Enumerate(const Slice &key) const override; + void RemoveRaw(const std::string &key); + + int lowest() const; + int highest() const; + + ~LayeredConfiguration(); + +private: + using ConfigList = std::list; + ConfigList configs_; +}; +} // namespace util +} // namespace tile + +#endif // TILE_BASE_CONFIG_LAYERED_CONFIGURATION_H diff --git a/tile/base/configuration.h b/tile/base/configuration.h new file mode 100644 index 0000000..0a980a9 --- /dev/null +++ b/tile/base/configuration.h @@ -0,0 +1,11 @@ +#ifndef TILE_BASE_CONFIGURATION_H +#define TILE_BASE_CONFIGURATION_H + +#pragma once + +#include "tile/base/config/configurable.h" +#include "tile/base/config/configuration.h" +#include "tile/base/config/ini_file_configuration.h" +#include "tile/base/config/layered_configuration.h" + +#endif // TILE_BASE_CONFIGURATION_H diff --git a/tile/tile.h b/tile/tile.h index 45a6cfd..288a809 100644 --- a/tile/tile.h +++ b/tile/tile.h @@ -9,7 +9,6 @@ #include "tile/base/casting.h" #include "tile/base/chrono.h" #include "tile/base/compression.h" -#include "tile/base/config/ini_file_config.h" #include "tile/base/data.h" #include "tile/base/deferred.h" #include "tile/base/demangle.h" @@ -40,13 +39,12 @@ #include "tile/base/write_mostly.h" // util -#include "tile/util/config.h" -#include "tile/util/ini_file_config.h" +#include "tile/base/configuration.h" // init module #include "tile/init/override_flag.h" -#include "sigslot/signal.h" +#include "sigslot/sigslot.h" // Tile Init #include "mustache.hpp" From 04d41aa566cfc88afedc7e442a02f7eab0737278 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Wed, 14 Aug 2024 22:42:06 +0800 Subject: [PATCH 02/25] feat add json configuration --- CMakeLists.txt | 1 + tile/base/config/configurable.h | 2 - tile/base/config/configuration.cc | 3 - tile/base/config/configuration.h | 2 - tile/base/config/ini_file_configuration.cc | 12 +- tile/base/config/ini_file_configuration.h | 2 - .../config/ini_file_configuration_test.cc | 2 - tile/base/config/json_configuration.cc | 128 ++++++++++++++++++ tile/base/config/json_configuration.h | 48 +++++++ tile/base/config/layered_configuration.cc | 2 - tile/base/config/layered_configuration.h | 2 - tile/tile.h | 1 - 12 files changed, 182 insertions(+), 23 deletions(-) create mode 100644 tile/base/config/json_configuration.cc create mode 100644 tile/base/config/json_configuration.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bbf65c9..23a459c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,6 +209,7 @@ set(TILE_SRCS # "tile/rpc/server.cc" "tile/base/config/configuration.cc" "tile/base/config/ini_file_configuration.cc" + "tile/base/config/json_configuration.cc" "tile/base/config/layered_configuration.cc" ) diff --git a/tile/base/config/configurable.h b/tile/base/config/configurable.h index 6896afd..6dc3969 100644 --- a/tile/base/config/configurable.h +++ b/tile/base/config/configurable.h @@ -5,7 +5,6 @@ #include "tile/base/string.h" namespace tile { -namespace util { class Configurable { Configurable(); virtual ~Configurable() = default; @@ -13,7 +12,6 @@ class Configurable { virtual std::string GetProperty(const Slice &name) const = 0; }; -} // namespace util } // namespace tile #endif // TILE_BASE_CONFIG_CONFIGURABLE_H diff --git a/tile/base/config/configuration.cc b/tile/base/config/configuration.cc index 482a93b..f501e78 100644 --- a/tile/base/config/configuration.cc +++ b/tile/base/config/configuration.cc @@ -2,7 +2,6 @@ #include "tile/base/thread/unique_lock.h" namespace tile { -namespace util { bool Configuration::Has(const Slice &key) const { UniqueLock lock(mutex_); std::string value; @@ -109,6 +108,4 @@ void Configuration::SetRawWithEvent(const Slice &key, Configuration::~Configuration() {} -} // namespace util - } // namespace tile diff --git a/tile/base/config/configuration.h b/tile/base/config/configuration.h index 2365340..a637de1 100644 --- a/tile/base/config/configuration.h +++ b/tile/base/config/configuration.h @@ -11,7 +11,6 @@ #include namespace tile { -namespace util { class Configuration : public RefCounted { public: using Keys = std::vector; @@ -121,7 +120,6 @@ private: mutable Mutex mutex_; bool events_enabled_{false}; }; -} // namespace util } // namespace tile #endif // TILE_BASE_CONFIG_CONFIGURATION_H diff --git a/tile/base/config/ini_file_configuration.cc b/tile/base/config/ini_file_configuration.cc index cb2c9bc..8bb1443 100644 --- a/tile/base/config/ini_file_configuration.cc +++ b/tile/base/config/ini_file_configuration.cc @@ -2,7 +2,6 @@ #include "tile/base/thread/scoped_lock.h" namespace tile { -namespace util { IniFileConfiguration::IniFileConfiguration() {} // IniFileConfig::IniFileConfig(std::istream &istr) { load(istr); } @@ -10,6 +9,10 @@ IniFileConfiguration::IniFileConfiguration() {} IniFileConfiguration::~IniFileConfiguration() {} bool IniFileConfiguration::load(std::istream &istr) { + if (!istr.good()) { + return false; + } + Configuration::ScopedLock lock(*this); map_.clear(); section_key_.clear(); @@ -20,11 +23,7 @@ bool IniFileConfiguration::load(std::istream &istr) { } bool IniFileConfiguration::load(const std::string &path) { std::ifstream istr(path); - if (istr.good()) { - return load(istr); - } else { - return false; - } + return load(istr); } bool IniFileConfiguration::GetRaw(const Slice &key, std::string *value) const { auto iter = map_.find(key.ToString()); @@ -141,5 +140,4 @@ bool IniFileConfiguration::ICompare::operator()(const std::string &s1, return strncmp(s1.c_str(), s2.c_str(), len) < 0; } -} // namespace util } // namespace tile diff --git a/tile/base/config/ini_file_configuration.h b/tile/base/config/ini_file_configuration.h index f9a1b08..218c1ac 100644 --- a/tile/base/config/ini_file_configuration.h +++ b/tile/base/config/ini_file_configuration.h @@ -7,7 +7,6 @@ #include namespace tile { -namespace util { class IniFileConfiguration : public Configuration { public: using Ptr = RefPtr; @@ -34,7 +33,6 @@ private: IStringMap map_; std::string section_key_; }; -} // namespace util } // namespace tile #endif // TILE_BASE_CONFIG_INI_FILE_CONFIG_H diff --git a/tile/base/config/ini_file_configuration_test.cc b/tile/base/config/ini_file_configuration_test.cc index ffd1de2..c8039c5 100644 --- a/tile/base/config/ini_file_configuration_test.cc +++ b/tile/base/config/ini_file_configuration_test.cc @@ -16,7 +16,6 @@ a=4 )"; namespace tile { -namespace util { static_assert( !detail::HasClassofImpl::value, ""); @@ -43,5 +42,4 @@ TEST(IniFileConfig, LoadFromIStream) { ASSERT_EQ(3, *config->GetInt("sec3.a")); ASSERT_EQ(4, *config->GetInt("sec2.kk.a")); } -} // namespace util } // namespace tile diff --git a/tile/base/config/json_configuration.cc b/tile/base/config/json_configuration.cc new file mode 100644 index 0000000..918f3ff --- /dev/null +++ b/tile/base/config/json_configuration.cc @@ -0,0 +1,128 @@ +#include "tile/base/config/json_configuration.h" +#include "tile/base/logging.h" + +namespace tile { +JSONConfiguration::JSONConfiguration() : object_() {} +JSONConfiguration::~JSONConfiguration() {} + +bool JSONConfiguration::load(const std::string &path) { + std::ifstream istr(path); + return load(istr); +} + +bool JSONConfiguration::load(std::istream &istr) { + if (!istr.good()) { + return false; + } + + Configuration::ScopedLock _(*this); + object_.clear(); + Json::Reader reader; + return reader.parse(istr, object_, true); +} + +void JSONConfiguration::SetInt(const Slice &key, int value) { + SetValue(key, value); +} + +void JSONConfiguration::SetBool(const Slice &key, bool value) { + SetValue(key, value); +} + +void JSONConfiguration::SetDouble(const Slice &key, double value) { + SetValue(key, value); +} + +void JSONConfiguration::SetString(const Slice &key, const std::string &value) { + SetValue(key, value); +} + +void JSONConfiguration::RemoveRaw(const Slice &key) { + Configuration::ScopedLock _(*this); + Json::Value root; + Slice last_part; + if (!FindStart(key, &last_part, &root)) { + return; + } + root.removeMember(last_part.ToString()); +} + +bool JSONConfiguration::GetRaw(const Slice &key, std::string *value) const { + Configuration::ScopedLock _(*this); + auto keys = Split(key, '.'); + auto root = object_; + for (std::size_t i = 0; i < keys.size(); ++i) { + const auto &cur_key = keys[i]; + if (cur_key.empty()) { + TILE_LOG_ERROR("Invalid key: {}", key); + return false; + } + if (!object_.isMember(cur_key)) { + return false; + } + root = root[cur_key]; + } + + *value = root.asString(); + return true; +} + +bool JSONConfiguration::SetRaw(const Slice &key, const Slice &value) { + return SetValue(key, value.ToString()); +} + +Configuration::Keys JSONConfiguration::Enumerate(const Slice &range) const { + Configuration::ScopedLock _(*this); + Configuration::Keys key_set; + + auto keys = Split(range, '.'); + auto root = object_; + for (std::size_t i = 0; i < keys.size(); ++i) { + const auto &cur_key = keys[i]; + if (cur_key.empty()) { + TILE_LOG_ERROR("Invalid range: {}", range); + return key_set; + } + if (!object_.isMember(cur_key)) { + return key_set; + } + root = root[cur_key]; + } + + for (const auto &key : root.getMemberNames()) { + key_set.push_back(key); + } + return key_set; +} + +bool JSONConfiguration::FindStart(const Slice &key, Slice *last_part, + Json::Value *parent_obj) { + auto keys = Split(key, '.'); + if (keys.empty()) { + return false; + } + + auto root = object_; + for (std::size_t i = 0; i < keys.size() - 1; ++i) { + const auto &cur_key = keys[i]; + if (cur_key.empty()) { + TILE_LOG_ERROR("Invalid key: {}", key); + return false; + } + + if (!root.isMember(cur_key)) { + root[cur_key] = Json::Value(Json::objectValue); + } else if (!root[cur_key].isObject()) { + TILE_LOG_ERROR("only leaf nodes can be set: key: {}, cur_key(idx={}): {}", + key, i, cur_key); + return false; + } + root = root[cur_key]; + } + + *last_part = keys.back(); + *parent_obj = root; + return true; +} + +} // namespace tile diff --git a/tile/base/config/json_configuration.h b/tile/base/config/json_configuration.h new file mode 100644 index 0000000..2208300 --- /dev/null +++ b/tile/base/config/json_configuration.h @@ -0,0 +1,48 @@ +#ifndef TILE_BASE_CONFIG_JSON_CONFIGURATION_H +#define TILE_BASE_CONFIG_JSON_CONFIGURATION_H + +#pragma once + +#include "tile/base/config/configuration.h" +#include "json/json.h" + +namespace tile { +class JSONConfiguration : public Configuration { +public: + using Ptr = RefPtr; + JSONConfiguration(); + ~JSONConfiguration() override; + bool load(const std::string &path); + bool load(std::istream &istr); + + void SetInt(const Slice &key, int value) override; + void SetBool(const Slice &key, bool value) override; + void SetDouble(const Slice &key, double value) override; + void SetString(const Slice &key, const std::string &value) override; + void RemoveRaw(const Slice &key) override; + +protected: + bool GetRaw(const Slice &key, std::string *value) const override; + bool SetRaw(const Slice &key, const Slice &value) override; + Keys Enumerate(const Slice &range) const override; + +private: + bool FindStart(const Slice &key, Slice *last_prt, Json::Value *parent_obj); + template bool SetValue(const Slice &key, T value); + Json::Value object_; +}; + +template +bool JSONConfiguration::SetValue(const Slice &key, T value) { + Slice last_part; + Json::Value root; + Configuration::ScopedLock _(*this); + if (!FindStart(key, &last_part, &root)) { + return false; + } + root[last_part] = Json::Value(value); + return true; +} +} // namespace tile + +#endif // TILE_BASE_CONFIG_JSON_CONFIGURATION_H diff --git a/tile/base/config/layered_configuration.cc b/tile/base/config/layered_configuration.cc index 80910ed..ea62c5e 100644 --- a/tile/base/config/layered_configuration.cc +++ b/tile/base/config/layered_configuration.cc @@ -1,7 +1,6 @@ #include "tile/base/config/layered_configuration.h" namespace tile { -namespace util { LayeredConfiguration::LayeredConfiguration() {} LayeredConfiguration::~LayeredConfiguration() {} @@ -129,5 +128,4 @@ int LayeredConfiguration::highest() const { } } -} // namespace util } // namespace tile diff --git a/tile/base/config/layered_configuration.h b/tile/base/config/layered_configuration.h index db498ff..aa8f9de 100644 --- a/tile/base/config/layered_configuration.h +++ b/tile/base/config/layered_configuration.h @@ -7,7 +7,6 @@ #include namespace tile { -namespace util { class LayeredConfiguration : public Configuration { public: using Ptr = RefPtr; @@ -51,7 +50,6 @@ private: using ConfigList = std::list; ConfigList configs_; }; -} // namespace util } // namespace tile #endif // TILE_BASE_CONFIG_LAYERED_CONFIGURATION_H diff --git a/tile/tile.h b/tile/tile.h index 288a809..3d89de1 100644 --- a/tile/tile.h +++ b/tile/tile.h @@ -47,7 +47,6 @@ #include "sigslot/sigslot.h" // Tile Init -#include "mustache.hpp" #include "tile/init.h" #endif // TILE_TILE_H From 5a02a4c7508b22abddcedc586565c5708b431bc4 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:12:06 +0800 Subject: [PATCH 03/25] fix json configuration --- .gitignore | 1 + CMakeLists.txt | 3 + tile/base/config/json_configuration.cc | 36 ++++++---- tile/base/config/json_configuration.h | 9 +-- tile/base/config/json_configuration_test.cc | 76 +++++++++++++++++++++ 5 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 tile/base/config/json_configuration_test.cc diff --git a/.gitignore b/.gitignore index 253e16b..6e95f64 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ out/ build/ .cache/ compile_commands.json +.gdb_history diff --git a/CMakeLists.txt b/CMakeLists.txt index 23a459c..405b12b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -302,6 +302,9 @@ function(add_test_group prefix group_name) # convert to relative path message(STATUS "${prefix} -> ${TEST_FILE}") file(RELATIVE_PATH TEST_NAME "${prefix}" "${SRC_FILE}") string(REPLACE "/" "_" TEST_NAME "${TEST_NAME}") + string(REPLACE ".cpp" "" TEST_NAME "${TEST_NAME}") + string(REPLACE ".cc" "" TEST_NAME "${TEST_NAME}") + string(REPLACE ".c" "" TEST_NAME "${TEST_NAME}") # if group_name is not empty, add suffix _ if (NOT group_name STREQUAL "") set(TEST_NAME "${group_name}_${TEST_NAME}") diff --git a/tile/base/config/json_configuration.cc b/tile/base/config/json_configuration.cc index 918f3ff..efdc238 100644 --- a/tile/base/config/json_configuration.cc +++ b/tile/base/config/json_configuration.cc @@ -22,33 +22,39 @@ bool JSONConfiguration::load(std::istream &istr) { } void JSONConfiguration::SetInt(const Slice &key, int value) { + Configuration::ScopedLock _(*this); SetValue(key, value); } void JSONConfiguration::SetBool(const Slice &key, bool value) { + Configuration::ScopedLock _(*this); SetValue(key, value); } void JSONConfiguration::SetDouble(const Slice &key, double value) { + Configuration::ScopedLock _(*this); SetValue(key, value); } void JSONConfiguration::SetString(const Slice &key, const std::string &value) { + Configuration::ScopedLock _(*this); SetValue(key, value); } void JSONConfiguration::RemoveRaw(const Slice &key) { - Configuration::ScopedLock _(*this); - Json::Value root; + Json::Value *root; Slice last_part; if (!FindStart(key, &last_part, &root)) { return; } - root.removeMember(last_part.ToString()); + root->removeMember(last_part.ToString()); +} +std::string JSONConfiguration::Dump() const { + Configuration::ScopedLock _(*this); + return object_.toStyledString(); } bool JSONConfiguration::GetRaw(const Slice &key, std::string *value) const { - Configuration::ScopedLock _(*this); auto keys = Split(key, '.'); auto root = object_; for (std::size_t i = 0; i < keys.size(); ++i) { @@ -57,13 +63,17 @@ bool JSONConfiguration::GetRaw(const Slice &key, std::string *value) const { TILE_LOG_ERROR("Invalid key: {}", key); return false; } - if (!object_.isMember(cur_key)) { + if (!root.isMember(cur_key)) { return false; } root = root[cur_key]; } - *value = root.asString(); + if (root.isConvertibleTo(Json::stringValue)) { + *value = root.asString(); + } else { + *value = root.toStyledString(); + } return true; } @@ -83,7 +93,7 @@ Configuration::Keys JSONConfiguration::Enumerate(const Slice &range) const { TILE_LOG_ERROR("Invalid range: {}", range); return key_set; } - if (!object_.isMember(cur_key)) { + if (!root.isMember(cur_key)) { return key_set; } root = root[cur_key]; @@ -96,13 +106,13 @@ Configuration::Keys JSONConfiguration::Enumerate(const Slice &range) const { } bool JSONConfiguration::FindStart(const Slice &key, Slice *last_part, - Json::Value *parent_obj) { + Json::Value **parent_obj) { auto keys = Split(key, '.'); if (keys.empty()) { return false; } - auto root = object_; + Json::Value *root = &object_; for (std::size_t i = 0; i < keys.size() - 1; ++i) { const auto &cur_key = keys[i]; if (cur_key.empty()) { @@ -110,14 +120,14 @@ bool JSONConfiguration::FindStart(const Slice &key, Slice *last_part, return false; } - if (!root.isMember(cur_key)) { - root[cur_key] = Json::Value(Json::objectValue); - } else if (!root[cur_key].isObject()) { + if (!root->isMember(cur_key)) { + (*root)[cur_key] = Json::Value(Json::objectValue); + } else if (!(*root)[cur_key].isObject()) { TILE_LOG_ERROR("only leaf nodes can be set: key: {}, cur_key(idx={}): {}", key, i, cur_key); return false; } - root = root[cur_key]; + root = &(*root)[cur_key]; } *last_part = keys.back(); diff --git a/tile/base/config/json_configuration.h b/tile/base/config/json_configuration.h index 2208300..be45c3a 100644 --- a/tile/base/config/json_configuration.h +++ b/tile/base/config/json_configuration.h @@ -21,13 +21,15 @@ public: void SetString(const Slice &key, const std::string &value) override; void RemoveRaw(const Slice &key) override; + std::string Dump() const; + protected: bool GetRaw(const Slice &key, std::string *value) const override; bool SetRaw(const Slice &key, const Slice &value) override; Keys Enumerate(const Slice &range) const override; private: - bool FindStart(const Slice &key, Slice *last_prt, Json::Value *parent_obj); + bool FindStart(const Slice &key, Slice *last_prt, Json::Value **parent_obj); template bool SetValue(const Slice &key, T value); Json::Value object_; }; @@ -35,12 +37,11 @@ private: template bool JSONConfiguration::SetValue(const Slice &key, T value) { Slice last_part; - Json::Value root; - Configuration::ScopedLock _(*this); + Json::Value *root; if (!FindStart(key, &last_part, &root)) { return false; } - root[last_part] = Json::Value(value); + (*root)[last_part] = Json::Value(value); return true; } } // namespace tile diff --git a/tile/base/config/json_configuration_test.cc b/tile/base/config/json_configuration_test.cc new file mode 100644 index 0000000..33be658 --- /dev/null +++ b/tile/base/config/json_configuration_test.cc @@ -0,0 +1,76 @@ +#include "tile/base/config/json_configuration.h" + +#include "gtest/gtest.h" + +namespace tile { +namespace { +const char *kJsonConfig = R"( + { + "key1": "value1", + "key2": 2, + "key3": 3.0, + "key4": true, + "key5": { + "key51": "value51", + "key52": 52 + } + } + )"; +} + +TEST(JSONConfiguration, Load) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); +} +TEST(JSONConfiguration, Has) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + + ASSERT_TRUE(config.Has("key1")); + ASSERT_TRUE(config.Has("key2")); + ASSERT_TRUE(config.Has("key3")); + ASSERT_TRUE(config.Has("key4")); + ASSERT_TRUE(config.Has("key5")); + ASSERT_TRUE(config.Has("key5.key51")); + ASSERT_TRUE(config.Has("key5.key52")); +} + +TEST(JSONConfiguration, SampleSet) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + ASSERT_TRUE(config.GetInt32("key2")); + ASSERT_EQ(*config.GetInt32("key2"), 2); + + config.SetInt("key2", 20); + ASSERT_TRUE(config.GetInt32("key2")); + ASSERT_EQ(20, *config.GetInt32("key2")) << config.Dump(); + + config.SetDouble("key3", 30.0); + ASSERT_TRUE(config.GetDouble("key3")); + ASSERT_NEAR(30.0, *config.GetDouble("key3"), 0.0001) << config.Dump(); + + config.SetBool("key4", false); + ASSERT_TRUE(config.GetBool("key4")); + ASSERT_FALSE(*config.GetBool("key4")) << config.Dump(); +} + +TEST(JSONConfiguration, LayeredSet) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + + // ASSERT_TRUE(config.GetInt32("key5.key52")); + config.SetInt("key5.key52", 520); + ASSERT_TRUE(config.GetInt32("key5.key52")) << config.Dump(); + ASSERT_EQ(520, *config.GetInt32("key5.key52")) << config.Dump(); + + // override by other type + config.SetBool("key5.key52", false); + ASSERT_TRUE(config.GetBool("key5.key52")) << config.Dump(); + ASSERT_FALSE(*config.GetBool("key5.key52")) << config.Dump(); +} + +} // namespace tile From 28c22939ce1fdc961af872de6608b80c83ab87a7 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:20:30 +0800 Subject: [PATCH 04/25] fix json configuration remove --- tile/base/config/configuration.cc | 11 ++++++++++- tile/base/config/json_configuration.cc | 9 ++++++--- tile/base/config/json_configuration_test.cc | 22 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/tile/base/config/configuration.cc b/tile/base/config/configuration.cc index f501e78..5e976e2 100644 --- a/tile/base/config/configuration.cc +++ b/tile/base/config/configuration.cc @@ -8,7 +8,16 @@ bool Configuration::Has(const Slice &key) const { return GetRaw(key, &value); } -void Configuration::Remove(const Slice &key) {} +void Configuration::Remove(const Slice &key) { + UniqueLock lock(mutex_); + if (events_enabled_) { + OnRemoving(key); + } + RemoveRaw(key); + if (events_enabled_) { + OnRemoved(key); + } +} void Configuration::EnableEvents(bool enable) { events_enabled_ = enable; } bool Configuration::EventsEnabled() const { return events_enabled_; } diff --git a/tile/base/config/json_configuration.cc b/tile/base/config/json_configuration.cc index efdc238..65f3e15 100644 --- a/tile/base/config/json_configuration.cc +++ b/tile/base/config/json_configuration.cc @@ -47,7 +47,7 @@ void JSONConfiguration::RemoveRaw(const Slice &key) { if (!FindStart(key, &last_part, &root)) { return; } - root->removeMember(last_part.ToString()); + root->removeMember(last_part); } std::string JSONConfiguration::Dump() const { Configuration::ScopedLock _(*this); @@ -82,8 +82,11 @@ bool JSONConfiguration::SetRaw(const Slice &key, const Slice &value) { } Configuration::Keys JSONConfiguration::Enumerate(const Slice &range) const { - Configuration::ScopedLock _(*this); Configuration::Keys key_set; + std::string prefix = range; + if (!prefix.empty()) { + prefix += "."; + } auto keys = Split(range, '.'); auto root = object_; @@ -100,7 +103,7 @@ Configuration::Keys JSONConfiguration::Enumerate(const Slice &range) const { } for (const auto &key : root.getMemberNames()) { - key_set.push_back(key); + key_set.push_back(prefix + key); } return key_set; } diff --git a/tile/base/config/json_configuration_test.cc b/tile/base/config/json_configuration_test.cc index 33be658..e213681 100644 --- a/tile/base/config/json_configuration_test.cc +++ b/tile/base/config/json_configuration_test.cc @@ -73,4 +73,26 @@ TEST(JSONConfiguration, LayeredSet) { ASSERT_FALSE(*config.GetBool("key5.key52")) << config.Dump(); } +TEST(json_configuration, Enumerate) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + auto keys = config.keys(""); + ASSERT_EQ(5, keys.size()); + ASSERT_EQ("key1", keys[0]); + ASSERT_EQ("key2", keys[1]); + ASSERT_EQ("key3", keys[2]); + ASSERT_EQ("key4", keys[3]); + ASSERT_EQ("key5", keys[4]); + + keys = config.keys("key5"); + ASSERT_EQ(2, keys.size()); + ASSERT_EQ("key5.key51", keys[0]); + ASSERT_EQ("key5.key52", keys[1]); + + config.Remove("key5.key51"); + keys = config.keys("key5"); + ASSERT_EQ("key5.key52", keys[0]); +} + } // namespace tile From a09f8cc68bca8104f4910a0d85462586a863322b Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:12:10 +0800 Subject: [PATCH 05/25] feat update --- .woodpecker/linux-aarch64-gcc.yml | 37 ------------------------------ .woodpecker/linux-arm-gcc.yml.stop | 30 ------------------------ .woodpecker/linux-x64-gcc.yml | 37 ------------------------------ .woodpecker/linux-x86-gcc.yml.stop | 36 ----------------------------- tile/base/config/configurable.h | 2 +- tile/base/config/configuration.cc | 2 ++ tile/base/config/configuration.h | 1 - 7 files changed, 3 insertions(+), 142 deletions(-) delete mode 100644 .woodpecker/linux-aarch64-gcc.yml delete mode 100644 .woodpecker/linux-arm-gcc.yml.stop delete mode 100644 .woodpecker/linux-x64-gcc.yml delete mode 100644 .woodpecker/linux-x86-gcc.yml.stop diff --git a/.woodpecker/linux-aarch64-gcc.yml b/.woodpecker/linux-aarch64-gcc.yml deleted file mode 100644 index 02f22df..0000000 --- a/.woodpecker/linux-aarch64-gcc.yml +++ /dev/null @@ -1,37 +0,0 @@ -when: - - event: - - push - - pull_request - - path: - include: - - ".woodpecker/linux-aarch64-gcc.yml" - - "cmake/**" - - "third_party/**" - - "tile/**" - - "CMakeLists.txt" - -matrix: - BUILD_TYPE: - - Debug - - Release - -steps: - - name: linux-aarch64-gcc-build - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - mkdir build - - cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DTILE_BUILD_BENCHMARKS=ON -DTILE_BUILD_TESTS=ON -DCMAKE_TOOLCHAIN_FILE=./toolchains/aarch64-linux-gnu.toolchain.cmake - - cmake --build build -j $(nproc) - - - name: linux-aarch64-gcc-test - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - cd build - - ctest --output-on-failure -j $(nproc) - - # - name: linux-aarch64-gcc-benchmark - # image: art.uocat.com/docker/tqcq/cross:v1.0.1 - # commands: - # - ./build/bin/tile_bm_all - - diff --git a/.woodpecker/linux-arm-gcc.yml.stop b/.woodpecker/linux-arm-gcc.yml.stop deleted file mode 100644 index 9a167bb..0000000 --- a/.woodpecker/linux-arm-gcc.yml.stop +++ /dev/null @@ -1,30 +0,0 @@ -when: - - event: [] - #- push - #- pull_request - -matrix: - BUILD_TYPE: - - Debug - - Release - -steps: - - name: linux-arm-gcc-build - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - mkdir build - - cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DTILE_BUILD_BENCHMARKS=ON -DTILE_BUILD_TESTS=ON -DCMAKE_TOOLCHAIN_FILE=./toolchains/arm-linux-gnueabihf.toolchain.cmake - - cmake --build build -j $(nproc) - - - name: linux-arm-gcc-test - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - cd build - - ctest --output-on-failure -j $(nproc) - - # - name: linux-arm-gcc-benchmark - # image: art.uocat.com/docker/tqcq/cross:v1.0.1 - # commands: - # - ./build/bin/tile_bm_all - - diff --git a/.woodpecker/linux-x64-gcc.yml b/.woodpecker/linux-x64-gcc.yml deleted file mode 100644 index 5b03d91..0000000 --- a/.woodpecker/linux-x64-gcc.yml +++ /dev/null @@ -1,37 +0,0 @@ -when: - - event: - - push - - pull_request - - path: - include: - - ".woodpecker/linux-x64-gcc.yml" - - "cmake/**" - - "third_party/**" - - "tile/**" - - "CMakeLists.txt" - -matrix: - BUILD_TYPE: - - Debug - - Release - -steps: - - name: linux-x64-gcc-build - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - mkdir build - - cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DTILE_BUILD_BENCHMARKS=ON -DTILE_BUILD_TESTS=ON - - cmake --build build -j $(nproc) - - - name: linux-x64-gcc-test - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - cd build - - ctest --output-on-failure -j $(nproc) - - - name: linux-x64-gcc-benchmark - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - ./build/bin/tile_bm_all - - diff --git a/.woodpecker/linux-x86-gcc.yml.stop b/.woodpecker/linux-x86-gcc.yml.stop deleted file mode 100644 index 80fbaf1..0000000 --- a/.woodpecker/linux-x86-gcc.yml.stop +++ /dev/null @@ -1,36 +0,0 @@ -when: - - event: - - push - - pull_request - - path: - include: - - ".woodpecker/linux-x86-gcc.yml" - - "cmake/**" - - "third_party/**" - - "tile/**" - - "CMakeLists.txt" -matrix: - BUILD_TYPE: - - Debug - - Release - -steps: - - name: linux-x86-gcc-build - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - mkdir build - - cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DTILE_BUILD_BENCHMARKS=ON -DTILE_BUILD_TESTS=ON -DCMAKE_TOOLCHAIN_FILE=./toolchains/host.gcc-m32.toolchain.cmake - - cmake --build build -j $(nproc) - - - name: linux-x86-gcc-test - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - cd build - - ctest --output-on-failure -j $(nproc) - - - name: linux-x86-gcc-benchmark - image: art.uocat.com/docker/tqcq/cross:v1.0.1 - commands: - - ./build/bin/tile_bm_all - - diff --git a/tile/base/config/configurable.h b/tile/base/config/configurable.h index 6dc3969..ddbca56 100644 --- a/tile/base/config/configurable.h +++ b/tile/base/config/configurable.h @@ -2,7 +2,7 @@ #define TILE_BASE_CONFIG_CONFIGURABLE_H #pragma once -#include "tile/base/string.h" +#include "tile/base/slice.h" namespace tile { class Configurable { diff --git a/tile/base/config/configuration.cc b/tile/base/config/configuration.cc index 5e976e2..dd921b0 100644 --- a/tile/base/config/configuration.cc +++ b/tile/base/config/configuration.cc @@ -1,4 +1,6 @@ #include "tile/base/config/configuration.h" + +#include "tile/base/string.h" #include "tile/base/thread/unique_lock.h" namespace tile { diff --git a/tile/base/config/configuration.h b/tile/base/config/configuration.h index a637de1..4484dad 100644 --- a/tile/base/config/configuration.h +++ b/tile/base/config/configuration.h @@ -5,7 +5,6 @@ #include "tile/base/optional.h" #include "tile/base/ref_ptr.h" #include "tile/base/slice.h" -#include "tile/base/string.h" #include "tile/base/thread/mutex.h" #include "tile/sigslot/sigslot.h" #include From 0ff288d0bce2b350f82efe1f9c1228ba6d02eeea Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:26:03 +0800 Subject: [PATCH 06/25] feat remove glog --- .clang-format | 78 ++++++++++++++++++++++++++++++++ tile/base/log/channel.h | 22 +++++++++ tile/base/log/logger.h | 11 +++++ tile/base/log/message.h | 98 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 .clang-format create mode 100644 tile/base/log/channel.h create mode 100644 tile/base/log/logger.h create mode 100644 tile/base/log/message.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6082673 --- /dev/null +++ b/.clang-format @@ -0,0 +1,78 @@ +# Generated from CLion C/C++ Code Style settings +BinPackParameters: false +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignArrayOfStructures: Left +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + +AlignOperands: DontAlign +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakTemplateDeclarations: Yes +# 函数和返回类型分两行,方便阅读 +AlwaysBreakAfterReturnType: TopLevelDefinitions +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +ConstructorInitializerAllOnOneLineOrOnePerLine: true +BreakInheritanceList: BeforeColon +ColumnLimit: 120 +CompactNamespaces: false +ContinuationIndentWidth: 4 +EmptyLineBeforeAccessModifier: LogicalBlock +SeparateDefinitionBlocks: Always +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PointerAlignment: Right +ReflowComments: false +SortIncludes: CaseSensitive +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never +PenaltyIndentedWhitespace: 1 diff --git a/tile/base/log/channel.h b/tile/base/log/channel.h new file mode 100644 index 0000000..a020502 --- /dev/null +++ b/tile/base/log/channel.h @@ -0,0 +1,22 @@ +#ifndef TILE_BASE_LOG_CHANNEL_H +#define TILE_BASE_LOG_CHANNEL_H + +#pragma once + +#include "tile/base/config/configurable.h" +#include "tile/base/ref_ptr.h" + +namespace tile { +namespace log { +class Channel : public Configurable, public RefCounted { +public: + void SetProperty(const Slice &name, const Slice &value) override; + std::string GetProperty(const Slice &name) const override; + +protected: + ~Channel() override; +}; +}// namespace log +};// namespace tile + +#endif// TILE_BASE_LOG_CHANNEL_H diff --git a/tile/base/log/logger.h b/tile/base/log/logger.h new file mode 100644 index 0000000..047d3c2 --- /dev/null +++ b/tile/base/log/logger.h @@ -0,0 +1,11 @@ +#ifndef TILE_BASE_LOG_LOGGER_H +#define TILE_BASE_LOG_LOGGER_H + +#pragma once + +namespace tile { +namespace log { +class Logger {}; +}// namespace log +}// namespace tile +#endif// TILE_BASE_LOG_LOGGER_H diff --git a/tile/base/log/message.h b/tile/base/log/message.h new file mode 100644 index 0000000..4bd8355 --- /dev/null +++ b/tile/base/log/message.h @@ -0,0 +1,98 @@ +#ifndef TILE_BASE_LOG_MESSAGE_H +#define TILE_BASE_LOG_MESSAGE_H + +#pragma once +#include +#include +#include + +namespace tile { +namespace log { +class Message { +public: + typedef std::map StringMap; + + enum Priority { + kTrace = 0, + kDebug, + kInfo, + kNotice, + kWarning, + kError, + kCritical, + kFatal, + }; + + Message(); + Message(const Message &other); + Message(Message &&other) noexcept; + ~Message(); + + Message &operator=(const Message &other); + Message &operator=(Message &&other) noexcept; + void swap(Message &other); + + // getter + inline const std::string &text() { return text_; } + + inline const std::string &source() const { return source_; } + + inline Priority priority() const { return priority_; } + + inline const std::string &thread_name() const { return thread_name_; } + + inline std::uint64_t tid() const { return tid_; } + + inline std::uint64_t pid() const { return pid_; } + + inline const char *source_file() const { return source_file_; } + + inline int source_line() const { return source_line_; } + + // setter + inline void set_text(const std::string &text) { text_ = text; } + + inline void set_source(const std::string &source) { source_ = source; } + + inline void set_priority(Priority priority) { priority_ = priority; } + + inline void set_thread_name(const std::string &thread) { thread_name_ = thread; } + + inline void set_tid(std::uint64_t tid) { tid_ = tid; } + + inline void set_pid(std::uint64_t pid) { pid_ = pid; } + + inline void set_source_file(const char *source_file) { source_file_ = source_file; } + + inline void set_source_line(int source_line) { source_line_ = source_line; } + + // map + const std::string &Get(const std::string ¶m) const; + const std::string &Get(const std::string ¶m, const std::string &defult_value) const; + const StringMap &GetAll() const; + void Set(const std::string ¶m, const std::string &value); + const std::string &operator[](const std::string ¶m) const; + std::string &operator[](const std::string ¶m); + +private: + std::string text_; + std::string source_; + Priority priority_; + std::string thread_name_; + std::uint64_t tid_; + std::uint64_t pid_; + const char *source_file_; + int source_line_; + StringMap properties_; +}; + +inline void +swap(Message &lhs, Message &rhs) +{ + lhs.swap(rhs); +} +}// namespace log + +}// namespace tile + +#endif// TILE_BASE_LOG_MESSAGE_H From dc2bb3567ba9bd0e0c23086fa6aa62b947515507 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:28:14 +0800 Subject: [PATCH 07/25] feat reinstall tools --- .gitea/workflows/linux-aarch64-gcc.yml | 12 ++++++------ .gitea/workflows/linux-arm-gcc.yml | 16 ++++++++-------- .gitea/workflows/linux-mips-gcc.yml | 12 ++++++------ .gitea/workflows/linux-mips64-gcc.yml | 12 ++++++------ .gitea/workflows/linux-riscv64-gcc.yml | 12 ++++++------ .gitea/workflows/linux-x64-clang.yml | 8 ++++---- .gitea/workflows/linux-x64-gcc.yml | 8 ++++---- 7 files changed, 40 insertions(+), 40 deletions(-) diff --git a/.gitea/workflows/linux-aarch64-gcc.yml b/.gitea/workflows/linux-aarch64-gcc.yml index cb9514b..7102486 100644 --- a/.gitea/workflows/linux-aarch64-gcc.yml +++ b/.gitea/workflows/linux-aarch64-gcc.yml @@ -38,10 +38,10 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - # - name: install-tools - # run: | - # sudo apt-get update -y - # sudo apt-get install -y g++-aarch64-linux-gnu qemu-user-binfmt + - name: install-tools + run: | + sudo apt-get update -y + sudo apt-get install -y g++-aarch64-linux-gnu qemu-user-binfmt - name: configure run: | mkdir build && cd build @@ -53,6 +53,6 @@ jobs: - name: test run: |- cd build - # sudo ln -sf /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 /lib/ld-linux-aarch64.so.1 - # export LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib + sudo ln -sf /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 /lib/ld-linux-aarch64.so.1 + export LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib ctest --output-on-failure -j $(nproc) diff --git a/.gitea/workflows/linux-arm-gcc.yml b/.gitea/workflows/linux-arm-gcc.yml index 24506b0..3b5cc01 100644 --- a/.gitea/workflows/linux-arm-gcc.yml +++ b/.gitea/workflows/linux-arm-gcc.yml @@ -36,10 +36,10 @@ jobs: build_type: ["Debug", "Release"] steps: - uses: actions/checkout@v4 - # - name: install-tools - # run: | - # sudo apt-get update -y - # sudo apt-get install -y g++-arm-linux-gnueabi qemu-user-binfmt + - name: install-tools + run: | + sudo apt-get update -y + sudo apt-get install -y g++-arm-linux-gnueabi qemu-user-binfmt - name: configure run: | mkdir build && cd build @@ -51,8 +51,8 @@ jobs: - name: test run: | cd build - #sudo ln -sf /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /lib/ld-linux.so.3 - #export LD_LIBRARY_PATH=/usr/arm-linux-gnueabi/lib + sudo ln -sf /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /lib/ld-linux.so.3 + export LD_LIBRARY_PATH=/usr/arm-linux-gnueabi/lib ctest --output-on-failure -j $(nproc) linux-gcc-armhf: @@ -79,6 +79,6 @@ jobs: - name: test run: |- cd build - # sudo ln -sf /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 /lib/ld-linux-armhf.so.3 - #export LD_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib/ + sudo ln -sf /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 /lib/ld-linux-armhf.so.3 + export LD_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib/ ctest --output-on-failure -j $(nproc) diff --git a/.gitea/workflows/linux-mips-gcc.yml b/.gitea/workflows/linux-mips-gcc.yml index 3b191b3..c59edef 100644 --- a/.gitea/workflows/linux-mips-gcc.yml +++ b/.gitea/workflows/linux-mips-gcc.yml @@ -35,10 +35,10 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - # - name: install-tools - # run: | - # sudo apt-get update -y - # sudo apt-get install -y g++-mipsel-linux-gnu qemu-user-binfmt + - name: install-tools + run: | + sudo apt-get update -y + sudo apt-get install -y g++-mipsel-linux-gnu qemu-user-binfmt - name: configure run: | mkdir build && cd build @@ -48,6 +48,6 @@ jobs: - name: test run: |- cd build - # sudo ln -sf /usr/mipsel-linux-gnu/lib/ld.so.1 /lib/ld.so.1 - # export LD_LIBRARY_PATH=/usr/mipsel-linux-gnu/lib/ + sudo ln -sf /usr/mipsel-linux-gnu/lib/ld.so.1 /lib/ld.so.1 + export LD_LIBRARY_PATH=/usr/mipsel-linux-gnu/lib/ ctest --output-on-failure -j $(nproc) diff --git a/.gitea/workflows/linux-mips64-gcc.yml b/.gitea/workflows/linux-mips64-gcc.yml index 96d82c5..a199aa9 100644 --- a/.gitea/workflows/linux-mips64-gcc.yml +++ b/.gitea/workflows/linux-mips64-gcc.yml @@ -36,10 +36,10 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - # - name: install-tools - # run: | - # sudo apt-get update -y - # sudo apt-get install -y g++-mips64el-linux-gnuabi64 qemu-user-binfmt + - name: install-tools + run: | + sudo apt-get update -y + sudo apt-get install -y g++-mips64el-linux-gnuabi64 qemu-user-binfmt - name: configure run: | mkdir build && cd build @@ -49,6 +49,6 @@ jobs: - name: test run: |- cd build - # sudo ln -sf /usr/mips64el-linux-gnuabi64/lib64/ld.so.1 /lib64/ld.so.1 - # export LD_LIBRARY_PATH=/usr/mips64el-linux-gnuabi64/lib + sudo ln -sf /usr/mips64el-linux-gnuabi64/lib64/ld.so.1 /lib64/ld.so.1 + export LD_LIBRARY_PATH=/usr/mips64el-linux-gnuabi64/lib ctest --output-on-failure -j $(nproc) diff --git a/.gitea/workflows/linux-riscv64-gcc.yml b/.gitea/workflows/linux-riscv64-gcc.yml index 61a829b..9e8be76 100644 --- a/.gitea/workflows/linux-riscv64-gcc.yml +++ b/.gitea/workflows/linux-riscv64-gcc.yml @@ -37,10 +37,10 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - # - name: install-tools - # run: | - # sudo apt-get update -y - # sudo apt-get install -y g++-riscv64-linux-gnu qemu-user-binfmt + - name: install-tools + run: | + sudo apt-get update -y + sudo apt-get install -y g++-riscv64-linux-gnu qemu-user-binfmt - name: configure run: | mkdir build && cd build @@ -50,6 +50,6 @@ jobs: - name: test run: |- cd build - # sudo ln -sf /usr/riscv64-linux-gnu/lib/ld-linux-riscv64-lp64d.so.1 /lib/ld-linux-riscv64-lp64d.so.1 - # export LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib + sudo ln -sf /usr/riscv64-linux-gnu/lib/ld-linux-riscv64-lp64d.so.1 /lib/ld-linux-riscv64-lp64d.so.1 + export LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib ctest --output-on-failure -j $(nproc) diff --git a/.gitea/workflows/linux-x64-clang.yml b/.gitea/workflows/linux-x64-clang.yml index 68373d5..0f282d0 100644 --- a/.gitea/workflows/linux-x64-clang.yml +++ b/.gitea/workflows/linux-x64-clang.yml @@ -29,10 +29,10 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - # - name: install-tools - # run: | - # sudo apt-get update -y - # sudo apt-get install -y cmake make + - name: install-tools + run: | + sudo apt-get update -y + sudo apt-get install -y cmake make - name: configure env: CC: clang diff --git a/.gitea/workflows/linux-x64-gcc.yml b/.gitea/workflows/linux-x64-gcc.yml index 0751dc1..752dcbd 100644 --- a/.gitea/workflows/linux-x64-gcc.yml +++ b/.gitea/workflows/linux-x64-gcc.yml @@ -33,10 +33,10 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - # - name: install-tools - # run: | - # sudo apt-get update -y - # sudo apt-get install -y cmake make + - name: install-tools + run: | + sudo apt-get update -y + sudo apt-get install -y cmake make - name: configure run: | mkdir build && cd build From 64200d42cc09ad2e017c055fa53b6f810aff6ca8 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:33:20 +0800 Subject: [PATCH 08/25] fix install cmake make --- .gitea/workflows/linux-aarch64-gcc.yml | 2 +- .gitea/workflows/linux-mips-gcc.yml | 2 +- .gitea/workflows/linux-mips64-gcc.yml | 2 +- .gitea/workflows/linux-riscv64-gcc.yml | 2 +- .gitea/workflows/linux-x86-gcc.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/linux-aarch64-gcc.yml b/.gitea/workflows/linux-aarch64-gcc.yml index 7102486..415d7fe 100644 --- a/.gitea/workflows/linux-aarch64-gcc.yml +++ b/.gitea/workflows/linux-aarch64-gcc.yml @@ -41,7 +41,7 @@ jobs: - name: install-tools run: | sudo apt-get update -y - sudo apt-get install -y g++-aarch64-linux-gnu qemu-user-binfmt + sudo apt-get install -y cmake make g++-aarch64-linux-gnu qemu-user-binfmt - name: configure run: | mkdir build && cd build diff --git a/.gitea/workflows/linux-mips-gcc.yml b/.gitea/workflows/linux-mips-gcc.yml index c59edef..c281183 100644 --- a/.gitea/workflows/linux-mips-gcc.yml +++ b/.gitea/workflows/linux-mips-gcc.yml @@ -38,7 +38,7 @@ jobs: - name: install-tools run: | sudo apt-get update -y - sudo apt-get install -y g++-mipsel-linux-gnu qemu-user-binfmt + sudo apt-get install -y cmake make g++-mipsel-linux-gnu qemu-user-binfmt - name: configure run: | mkdir build && cd build diff --git a/.gitea/workflows/linux-mips64-gcc.yml b/.gitea/workflows/linux-mips64-gcc.yml index a199aa9..4531e39 100644 --- a/.gitea/workflows/linux-mips64-gcc.yml +++ b/.gitea/workflows/linux-mips64-gcc.yml @@ -39,7 +39,7 @@ jobs: - name: install-tools run: | sudo apt-get update -y - sudo apt-get install -y g++-mips64el-linux-gnuabi64 qemu-user-binfmt + sudo apt-get install -y cmake make g++-mips64el-linux-gnuabi64 qemu-user-binfmt - name: configure run: | mkdir build && cd build diff --git a/.gitea/workflows/linux-riscv64-gcc.yml b/.gitea/workflows/linux-riscv64-gcc.yml index 9e8be76..b7fa618 100644 --- a/.gitea/workflows/linux-riscv64-gcc.yml +++ b/.gitea/workflows/linux-riscv64-gcc.yml @@ -40,7 +40,7 @@ jobs: - name: install-tools run: | sudo apt-get update -y - sudo apt-get install -y g++-riscv64-linux-gnu qemu-user-binfmt + sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-binfmt - name: configure run: | mkdir build && cd build diff --git a/.gitea/workflows/linux-x86-gcc.yml b/.gitea/workflows/linux-x86-gcc.yml index 76d1b77..19710af 100644 --- a/.gitea/workflows/linux-x86-gcc.yml +++ b/.gitea/workflows/linux-x86-gcc.yml @@ -38,7 +38,7 @@ jobs: - name: install-tools run: | sudo apt-get update -y - sudo apt-get install -y gcc-multilib g++-multilib + sudo apt-get install -y cmake make gcc-multilib g++-multilib - name: configure run: | mkdir build && cd build From 481015e1c699a5f1c2fe7105404974f7bb94ba14 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:40:44 +0800 Subject: [PATCH 09/25] feat format file --- .gitea/workflows/linux-x64-clang.yml | 2 +- tile/base/align.h | 16 +- tile/base/buffer.cc | 410 +- tile/base/buffer.h | 547 ++- tile/base/buffer/builtin_buffer_block.cc | 152 +- tile/base/buffer/builtin_buffer_block.h | 36 +- tile/base/buffer/circular_buffer.h | 84 +- tile/base/buffer/compression_output_stream.cc | 63 +- tile/base/buffer/compression_output_stream.h | 22 +- tile/base/buffer/polymorphic_buffer.cc | 18 +- tile/base/buffer/polymorphic_buffer.h | 155 +- tile/base/buffer_test.cc | 477 +- tile/base/byte_order.h | 88 +- tile/base/byte_order_test.cc | 126 +- tile/base/casting.h | 262 +- tile/base/casting_benchmark.cc | 49 +- tile/base/casting_test.cc | 108 +- tile/base/chrono.cc | 206 +- tile/base/chrono.h | 37 +- tile/base/chrono_benchmark.cc | 68 +- tile/base/chrono_test.cc | 56 +- tile/base/compression.cc | 149 +- tile/base/compression.h | 25 +- tile/base/compression/compression.cc | 42 +- tile/base/compression/compression.h | 55 +- tile/base/compression/gzip.cc | 426 +- tile/base/compression/gzip.h | 45 +- tile/base/compression/util.cc | 54 +- tile/base/compression/util.h | 7 +- tile/base/compression/util_test.cc | 25 +- tile/base/compression_test.cc | 97 +- tile/base/config/configurable.h | 12 +- tile/base/config/configuration.cc | 168 +- tile/base/config/configuration.h | 176 +- tile/base/config/ini_file_configuration.cc | 249 +- tile/base/config/ini_file_configuration.h | 44 +- .../config/ini_file_configuration_test.cc | 46 +- tile/base/config/json_configuration.cc | 236 +- tile/base/config/json_configuration.h | 57 +- tile/base/config/json_configuration_test.cc | 136 +- tile/base/config/layered_configuration.cc | 216 +- tile/base/config/layered_configuration.h | 67 +- tile/base/configuration.h | 2 +- tile/base/data.h | 2 +- tile/base/data/json.h | 42 +- tile/base/deferred.h | 67 +- tile/base/deferred_test.cc | 78 +- tile/base/demangle.cc | 20 +- tile/base/demangle.h | 18 +- tile/base/demangle_test.cc | 18 +- tile/base/dependency_registry.h | 302 +- tile/base/dependency_registry_test.cc | 95 +- tile/base/down_cast.h | 26 +- tile/base/down_cast_test.cc | 25 +- tile/base/encoding.h | 2 +- tile/base/encoding/base64.cc | 241 +- tile/base/encoding/base64.h | 4 +- tile/base/encoding/base64_test.cc | 125 +- tile/base/encoding/detail/base64_impl.h | 425 +- tile/base/encoding/detail/hex_chars.cc | 126 +- tile/base/encoding/detail/hex_chars.h | 11 +- tile/base/encoding/hex.cc | 71 +- tile/base/encoding/hex.h | 4 +- tile/base/encoding/hex_test.cc | 34 +- tile/base/encoding/percent.cc | 175 +- tile/base/encoding/percent.h | 32 +- tile/base/encoding/percent_test.cc | 160 +- tile/base/encoding_benchmark.cc | 139 +- tile/base/enum.h | 52 +- tile/base/erased_ptr.h | 97 +- tile/base/expected.h | 4305 ++++++++--------- tile/base/exposed_var.cc | 419 +- tile/base/exposed_var.h | 237 +- tile/base/exposed_var_test.cc | 43 +- tile/base/future.h | 4 +- tile/base/future/basic.h | 109 +- tile/base/future/boxed.h | 226 +- tile/base/future/boxed_test.cc | 93 +- tile/base/future/core.h | 127 +- tile/base/future/executor.h | 135 +- tile/base/future/future-impl.h | 172 +- tile/base/future/future.h | 93 +- tile/base/future/future_test.cc | 475 +- tile/base/future/impls.h | 69 +- tile/base/future/promise-impl.h | 42 +- tile/base/future/promise.h | 48 +- tile/base/future/split.h | 68 +- tile/base/future/types.h | 91 +- tile/base/future/utils.h | 203 +- tile/base/future/when_all.h | 292 +- tile/base/future/when_any.h | 89 +- tile/base/handle.h | 123 +- tile/base/handle_test.cc | 36 +- tile/base/id_alloc.h | 106 +- tile/base/internal/background_task_host.cc | 67 +- tile/base/internal/background_task_host.h | 22 +- .../internal/background_task_host_test.cc | 33 +- .../base/internal/case_insensitive_hash_map.h | 36 +- .../case_insensitive_hash_map_test.cc | 27 +- tile/base/internal/curl.cc | 204 +- tile/base/internal/curl.h | 27 +- tile/base/internal/curl_test.cc | 172 +- tile/base/internal/early_init.h | 22 +- tile/base/internal/format.h | 124 +- tile/base/internal/format_test.cc | 58 +- tile/base/internal/index_alloc.cc | 30 +- tile/base/internal/index_alloc.h | 32 +- tile/base/internal/lazy_init.h | 24 +- tile/base/internal/logging.cc | 290 +- tile/base/internal/logging.h | 820 ++-- tile/base/internal/logging_test.cc | 143 +- tile/base/internal/macro.h | 38 +- tile/base/internal/macro_inl.h | 2 +- tile/base/internal/meta.h | 154 +- tile/base/internal/meta/apply.h | 121 +- tile/base/internal/meta/base.h | 18 +- tile/base/internal/meta/index_sequence.h | 52 +- tile/base/internal/meta/invoke.h | 336 +- tile/base/internal/meta_test.cc | 94 +- tile/base/internal/move_on_copy.h | 87 +- tile/base/internal/move_on_copy_test.cc | 77 +- tile/base/internal/mutex.h | 296 +- tile/base/internal/optional.h | 3044 ++++++------ tile/base/internal/singly_linked_list.h | 416 +- tile/base/internal/singly_linked_list_test.cc | 251 +- tile/base/internal/test_prod.h | 7 +- tile/base/internal/thread_pool.cc | 113 +- tile/base/internal/thread_pool.h | 29 +- tile/base/internal/thread_pool_test.cc | 41 +- tile/base/internal/time_keeper.cc | 214 +- tile/base/internal/time_keeper.h | 119 +- tile/base/internal/time_keeper_benchmark.cc | 60 +- tile/base/internal/time_keeper_test.cc | 66 +- tile/base/internal/utility.h | 25 +- tile/base/internal/variant.h | 3521 +++++++------- tile/base/likely.h | 2 +- tile/base/logging.h | 2 +- tile/base/make_unique.h | 65 +- tile/base/maybe_owning.h | 213 +- tile/base/maybe_owning_test.cc | 296 +- tile/base/net/detail/android/ifaddrs.h | 2 +- tile/base/net/endpoint.cc | 724 +-- tile/base/net/endpoint.h | 175 +- tile/base/net/endpoint_test.cc | 280 +- tile/base/net/uri.h | 71 +- tile/base/never_destroyed.h | 74 +- tile/base/object_pool.h | 302 +- tile/base/object_pool/disabled.cc | 22 +- tile/base/object_pool/disabled.h | 10 +- tile/base/object_pool/disabled_test.cc | 33 +- tile/base/object_pool/global.cc | 24 +- tile/base/object_pool/global.h | 10 +- tile/base/object_pool/thread_local.cc | 159 +- tile/base/object_pool/thread_local.h | 64 +- tile/base/object_pool/thread_local_test.cc | 153 +- tile/base/object_pool/types.h | 336 +- tile/base/object_pool/types_test.cc | 168 +- tile/base/option.cc | 32 +- tile/base/option.h | 152 +- tile/base/option/dynamically_changed.h | 38 +- tile/base/option/gflags_provider.cc | 72 +- tile/base/option/json_parser.cc | 22 +- tile/base/option/json_parser.h | 8 +- tile/base/option/json_parser_test.cc | 15 +- tile/base/option/key.cc | 95 +- tile/base/option/key.h | 161 +- tile/base/option/key_test.cc | 49 +- tile/base/option/option_impl.h | 131 +- tile/base/option/option_provider.cc | 3 +- tile/base/option/option_provider.h | 71 +- tile/base/option/option_service.cc | 294 +- tile/base/option/option_service.h | 142 +- tile/base/option/option_service_test.cc | 25 +- tile/base/optional.h | 3 +- tile/base/random.h | 55 +- tile/base/ref_ptr.h | 392 +- tile/base/ref_ptr_test.cc | 221 +- tile/base/slice.cc | 17 +- tile/base/slice.h | 330 +- tile/base/status.cc | 46 +- tile/base/status.h | 39 +- tile/base/status_test.cc | 47 +- tile/base/string.cc | 599 +-- tile/base/string.h | 93 +- tile/base/string_test.cc | 501 +- tile/base/thread/cond_var.cc | 80 +- tile/base/thread/cond_var.h | 172 +- tile/base/thread/cond_var_test.cc | 203 +- tile/base/thread/event.h | 91 +- tile/base/thread/latch.cc | 49 +- tile/base/thread/latch.h | 47 +- tile/base/thread/latch_test.cc | 94 +- tile/base/thread/mutex.cc | 75 +- tile/base/thread/mutex.h | 46 +- tile/base/thread/mutex_benchmark.cc | 85 +- tile/base/thread/rw_mutex.cc | 222 +- tile/base/thread/rw_mutex.h | 69 +- tile/base/thread/scoped_lock.cc | 130 +- tile/base/thread/scoped_lock.h | 136 +- tile/base/thread/scoped_lock_test.cc | 665 +-- tile/base/thread/spinlock.cc | 22 +- tile/base/thread/spinlock.h | 25 +- tile/base/thread/spinlock_test.cc | 41 +- tile/base/thread/thread_local.h | 2 +- tile/base/thread/thread_local/object_array.h | 2 +- tile/base/thread/unique_lock.h | 66 +- tile/base/thread/unique_lock_test.cc | 85 +- tile/base/type_index.h | 60 +- tile/base/variant.h | 3 +- tile/base/write_mostly/metrics.h | 31 +- tile/base/write_mostly/write_mostly.h | 9 +- tile/init.cc | 140 +- tile/init.h | 11 +- tile/init/on_init.cc | 124 +- tile/init/on_init.h | 44 +- tile/init/on_init_test.cc | 8 +- tile/init/override_flag.cc | 58 +- tile/init/override_flag.h | 43 +- tile/init/override_flag_test.cc | 4 +- tile/io/acceptor.h | 10 +- tile/io/descriptor.cc | 505 +- tile/io/descriptor.h | 122 +- tile/io/detail/eintr_safe.cc | 34 +- tile/io/detail/eintr_safe.h | 69 +- tile/io/event_loop.cc | 72 +- tile/io/event_loop.h | 42 +- tile/io/native/acceptor.cc | 91 +- tile/io/native/acceptor.h | 26 +- tile/io/util/rate_limiter.cc | 123 +- tile/io/util/rate_limiter.h | 63 +- tile/io/util/rate_limiter_test.cc | 311 +- tile/net/http/http_client.cc | 934 ++-- tile/net/http/http_client.h | 215 +- tile/net/http/http_client_test.cc | 82 +- tile/net/http/http_headers.cc | 229 +- tile/net/http/http_headers.h | 118 +- tile/net/http/http_headers_test.cc | 88 +- tile/net/http/http_message.cc | 20 +- tile/net/http/http_message.h | 91 +- tile/net/http/http_reqeust_test.cc | 150 +- tile/net/http/http_request.cc | 44 +- tile/net/http/http_request.h | 36 +- tile/net/http/http_response.cc | 251 +- tile/net/http/http_response.h | 32 +- tile/net/http/http_response_test.cc | 110 +- tile/net/http/packet_desc.h | 6 +- tile/net/http/types.cc | 237 +- tile/net/http/types.h | 138 +- tile/net/internal/http_engine.cc | 527 +- tile/net/internal/http_engine.h | 20 +- tile/net/internal/http_engine_test.cc | 46 +- tile/net/internal/http_task.cc | 358 +- tile/net/internal/http_task.h | 109 +- tile/net/internal/http_task_test.cc | 30 +- tile/rpc/protocol/http/buffer_io.cc | 460 +- tile/rpc/protocol/http/buffer_io.h | 18 +- tile/rpc/protocol/http/buffer_io_test.cc | 387 +- tile/rpc/protocol/message.cc | 15 +- tile/rpc/protocol/message.h | 39 +- tile/rpc/server.cc | 45 +- tile/rpc/server.h | 151 +- tile/sigslot/sigslot.h | 2296 +++++---- tile/testing/bm_main.h | 12 +- tile/testing/internal/random_string.cc | 8 +- tile/testing/internal/random_string.h | 79 +- tile/testing/main.cc | 18 +- tile/testing/main.h | 12 +- tile/tile.h | 2 +- 268 files changed, 23084 insertions(+), 22201 deletions(-) diff --git a/.gitea/workflows/linux-x64-clang.yml b/.gitea/workflows/linux-x64-clang.yml index 0f282d0..639234c 100644 --- a/.gitea/workflows/linux-x64-clang.yml +++ b/.gitea/workflows/linux-x64-clang.yml @@ -32,7 +32,7 @@ jobs: - name: install-tools run: | sudo apt-get update -y - sudo apt-get install -y cmake make + sudo apt-get install -y cmake make clang-tools - name: configure env: CC: clang diff --git a/tile/base/align.h b/tile/base/align.h index 05d498c..7adbbd8 100644 --- a/tile/base/align.h +++ b/tile/base/align.h @@ -15,19 +15,19 @@ constexpr std::size_t max_align_v = alignof(max_align_t); // @sa: https://github.com/facebook/folly/blob/master/folly/lang/Align.h // // Update at 20201124: Well, AMD's Zen 3 does the same. -constexpr std::size_t hardware_destructive_interference_size = 128; +constexpr std::size_t hardware_destructive_interference_size = 128; constexpr std::size_t hardware_constructive_interference_size = 64; #elif defined(__powerpc64__) // These values are read from // `/sys/devices/system/cpu/cpu0/cache/index*/coherency_line_size` -constexpr std::size_t hardware_destructive_interference_size = 128; +constexpr std::size_t hardware_destructive_interference_size = 128; constexpr std::size_t hardware_constructive_interference_size = 128; #elif defined(__ARM_ARCH_5T__) -constexpr std::size_t hardware_destructive_interference_size = 32; +constexpr std::size_t hardware_destructive_interference_size = 32; constexpr std::size_t hardware_constructive_interference_size = 32; #elif defined(__arm__) @@ -36,7 +36,7 @@ constexpr std::size_t hardware_constructive_interference_size = 32; // are even implementations with cache line sizes configurable at boot // time. -constexpr std::size_t hardware_destructive_interference_size = 64; +constexpr std::size_t hardware_destructive_interference_size = 64; constexpr std::size_t hardware_constructive_interference_size = 64; #elif defined(__aarch64__) @@ -47,13 +47,13 @@ constexpr std::size_t hardware_constructive_interference_size = 64; // Let's ignore those CPUs for now. // // @sa: https://www.mono-project.com/news/2016/09/12/arm64-icache/ -constexpr std::size_t hardware_destructive_interference_size = 64; +constexpr std::size_t hardware_destructive_interference_size = 64; constexpr std::size_t hardware_constructive_interference_size = 64; #else constexpr std::size_t hardware_constructive_interference_size = max_align_v; -constexpr std::size_t hardware_destructive_interference_size = max_align_v; +constexpr std::size_t hardware_destructive_interference_size = max_align_v; // #error Unsupported architecture. // #pragma message("Unsupported architecture, use max_align_v") @@ -62,6 +62,6 @@ static_assert(hardware_constructive_interference_size >= max_align_v, "hardware constructive interference size is too small"); static_assert(hardware_destructive_interference_size >= max_align_v, "hardware destructive interference size is too small"); -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_ALIGN_H +#endif// _TILE_BASE_ALIGN_H diff --git a/tile/base/buffer.cc b/tile/base/buffer.cc index 3eb688d..a7fbd5e 100644 --- a/tile/base/buffer.cc +++ b/tile/base/buffer.cc @@ -9,205 +9,214 @@ namespace tile { namespace { -template class OwningBufferBlock : public PolymorphicBufferBlock { +template +class OwningBufferBlock : public PolymorphicBufferBlock { public: - explicit OwningBufferBlock(T storage) : storage_(std::move(storage)) {} - const char *data() const noexcept override { - return reinterpret_cast(storage_.data()); - } + explicit OwningBufferBlock(T storage) : storage_(std::move(storage)) {} - std::size_t size() const noexcept override { return storage_.size(); } + const char *data() const noexcept override { return reinterpret_cast(storage_.data()); } + + std::size_t size() const noexcept override { return storage_.size(); } private: - T storage_; + T storage_; }; -} // namespace +}// namespace namespace detail { -void FlattenToSlowSlow(const NoncontiguousBuffer &nb, void *buffer, - std::size_t size) { - TILE_CHECK_GT(nb.ByteSize(), size, "No enough data"); - std::size_t copied = 0; - for (auto iter = nb.begin(); iter != nb.end() && copied != size; ++iter) { - auto len = std::min(size - copied, iter->size()); - memcpy(reinterpret_cast(buffer) + copied, iter->data(), len); - copied += len; - } +void +FlattenToSlowSlow(const NoncontiguousBuffer &nb, void *buffer, std::size_t size) +{ + TILE_CHECK_GT(nb.ByteSize(), size, "No enough data"); + std::size_t copied = 0; + for (auto iter = nb.begin(); iter != nb.end() && copied != size; ++iter) { + auto len = std::min(size - copied, iter->size()); + memcpy(reinterpret_cast(buffer) + copied, iter->data(), len); + copied += len; + } } -} // namespace detail +}// namespace detail -NoncontiguousBuffer::NoncontiguousBuffer(const NoncontiguousBuffer &other) - : byte_size_(other.byte_size_) { - for (auto &&e : other.buffers_) { +NoncontiguousBuffer::NoncontiguousBuffer(const NoncontiguousBuffer &other) : byte_size_(other.byte_size_) +{ + for (auto &&e : other.buffers_) { - auto b = object_pool::Get().Leak(); - *b = e; - buffers_.push_back(std::move(b)); - } + auto b = object_pool::Get().Leak(); + *b = e; + buffers_.push_back(std::move(b)); + } } NoncontiguousBuffer & -NoncontiguousBuffer::operator=(const NoncontiguousBuffer &other) { - if (TILE_UNLIKELY(&other == this)) { +NoncontiguousBuffer::operator=(const NoncontiguousBuffer &other) +{ + if (TILE_UNLIKELY(&other == this)) { return *this; } + + Clear(); + byte_size_ = other.byte_size_; + for (auto &&e : other.buffers_) { + + auto b = object_pool::Get().Leak(); + *b = e; + buffers_.push_back(std::move(b)); + } return *this; - } - - Clear(); - byte_size_ = other.byte_size_; - for (auto &&e : other.buffers_) { - - auto b = object_pool::Get().Leak(); - *b = e; - buffers_.push_back(std::move(b)); - } - return *this; } -void NoncontiguousBuffer::SkipSlow(std::size_t bytes) noexcept { - TILE_CHECK_LE(bytes, byte_size_, "Skip bytes exceed buffer size"); - byte_size_ -= bytes; +void +NoncontiguousBuffer::SkipSlow(std::size_t bytes) noexcept +{ + TILE_CHECK_LE(bytes, byte_size_, "Skip bytes exceed buffer size"); + byte_size_ -= bytes; - while (bytes) { - auto &&first = buffers_.front(); - auto min_size = std::min(bytes, first.size()); - if (min_size == first.size()) { - object_pool::Put(buffers_.pop_front()); - } else { - TILE_DCHECK_LT(min_size, first.size()); - first.Skip(min_size); + while (bytes) { + auto &&first = buffers_.front(); + auto min_size = std::min(bytes, first.size()); + if (min_size == first.size()) { + object_pool::Put(buffers_.pop_front()); + } else { + TILE_DCHECK_LT(min_size, first.size()); + first.Skip(min_size); + } + bytes -= min_size; } - bytes -= min_size; - } } -void NoncontiguousBuffer::ClearSlow() noexcept { - byte_size_ = 0; - while (!buffers_.empty()) { - object_pool::Put(buffers_.pop_front()); - } +void +NoncontiguousBuffer::ClearSlow() noexcept +{ + byte_size_ = 0; + while (!buffers_.empty()) { object_pool::Put(buffers_.pop_front()); } } -void NoncontiguousBufferBuilder::InitializeNextBlock() { - if (current_) { - TILE_CHECK(SizeAvailable(), - "You should flush current block by `FlushCurrentBlock()`"); - return; - } - - current_ = MakeNativeBufferBlock(); - used_ = 0; -} - -void NoncontiguousBufferBuilder::FlushCurrentBlock() { - if (!used_) { - // current block is empty - return; - } - - nb_.Append(PolymorphicBuffer(std::move(current_), 0, used_)); - used_ = 0; - current_ = nullptr; -} - -void NoncontiguousBufferBuilder::AppendSlow(const void *ptr, - std::size_t length) { - while (length) { - auto copying = std::min(length, SizeAvailable()); - memcpy(data(), ptr, copying); - MarkWritten(copying); - ptr = static_cast(ptr) + copying; - length -= copying; - } -} - -void NoncontiguousBufferBuilder::AppendCopy(const NoncontiguousBuffer &buffer) { - for (auto &&e : buffer) { - Append(e.data(), e.size()); - } -} - -NoncontiguousBuffer CreateBufferSlow(Slice s) { - NoncontiguousBufferBuilder nbb; - nbb.Append(s); - return nbb.DestructiveGet(); -} -NoncontiguousBuffer CreateBufferSlow(const void *ptr, std::size_t size) { - NoncontiguousBufferBuilder nbb; - nbb.Append(ptr, size); - return nbb.DestructiveGet(); -} - -std::string FlattenSlow(const NoncontiguousBuffer &nb, std::size_t max_bytes) { - max_bytes = std::min(max_bytes, nb.ByteSize()); - std::string rc; - std::size_t left = max_bytes; - rc.reserve(max_bytes); - for (auto iter = nb.begin(); iter != nb.end() && left; ++iter) { - auto len = std::min(left, iter->size()); - rc.append(iter->data(), len); - left -= len; - } - return rc; -} - -std::string FlattenSlowUntil(const NoncontiguousBuffer &nb, Slice delim, - std::size_t max_bytes) { - if (nb.Empty()) { - return {}; - } - - { - Slice current(nb.FirstContiguous().data(), nb.FirstContiguous().size()); - auto pos = current.find(delim); - if (pos != Slice::npos) { - auto expected_bytes = std::min(pos + delim.size(), max_bytes); - return std::string(nb.FirstContiguous().data(), - nb.FirstContiguous().data() + expected_bytes); +void +NoncontiguousBufferBuilder::InitializeNextBlock() +{ + if (current_) { + TILE_CHECK(SizeAvailable(), "You should flush current block by `FlushCurrentBlock()`"); + return; } - } - std::string rc; - for (auto iter = nb.begin(); iter != nb.end() && rc.size() < max_bytes; - ++iter) { - auto old_len = rc.size(); - rc.append(iter->data(), iter->size()); - // find delim + current_ = MakeNativeBufferBlock(); + used_ = 0; +} + +void +NoncontiguousBufferBuilder::FlushCurrentBlock() +{ + if (!used_) { + // current block is empty + return; + } + + nb_.Append(PolymorphicBuffer(std::move(current_), 0, used_)); + used_ = 0; + current_ = nullptr; +} + +void +NoncontiguousBufferBuilder::AppendSlow(const void *ptr, std::size_t length) +{ + while (length) { + auto copying = std::min(length, SizeAvailable()); + memcpy(data(), ptr, copying); + MarkWritten(copying); + ptr = static_cast(ptr) + copying; + length -= copying; + } +} + +void +NoncontiguousBufferBuilder::AppendCopy(const NoncontiguousBuffer &buffer) +{ + for (auto &&e : buffer) { Append(e.data(), e.size()); } +} + +NoncontiguousBuffer +CreateBufferSlow(Slice s) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append(s); + return nbb.DestructiveGet(); +} + +NoncontiguousBuffer +CreateBufferSlow(const void *ptr, std::size_t size) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append(ptr, size); + return nbb.DestructiveGet(); +} + +std::string +FlattenSlow(const NoncontiguousBuffer &nb, std::size_t max_bytes) +{ + max_bytes = std::min(max_bytes, nb.ByteSize()); + std::string rc; + std::size_t left = max_bytes; + rc.reserve(max_bytes); + for (auto iter = nb.begin(); iter != nb.end() && left; ++iter) { + auto len = std::min(left, iter->size()); + rc.append(iter->data(), len); + left -= len; + } + return rc; +} + +std::string +FlattenSlowUntil(const NoncontiguousBuffer &nb, Slice delim, std::size_t max_bytes) +{ + if (nb.Empty()) { return {}; } + { - // Avoiding the use of find_last_of - auto pos = rc.find(delim, old_len - std::min(old_len, delim.size())); - if (pos != Slice::npos) { - rc.erase(rc.begin() + pos + delim.size(), rc.end()); - break; - } + Slice current(nb.FirstContiguous().data(), nb.FirstContiguous().size()); + auto pos = current.find(delim); + if (pos != Slice::npos) { + auto expected_bytes = std::min(pos + delim.size(), max_bytes); + return std::string(nb.FirstContiguous().data(), nb.FirstContiguous().data() + expected_bytes); + } } - } - if (rc.size() > max_bytes) { - rc.erase(rc.begin() + max_bytes, rc.end()); - } - return rc; + + std::string rc; + for (auto iter = nb.begin(); iter != nb.end() && rc.size() < max_bytes; ++iter) { + auto old_len = rc.size(); + rc.append(iter->data(), iter->size()); + // find delim + { + // Avoiding the use of find_last_of + auto pos = rc.find(delim, old_len - std::min(old_len, delim.size())); + if (pos != Slice::npos) { + rc.erase(rc.begin() + pos + delim.size(), rc.end()); + break; + } + } + } + if (rc.size() > max_bytes) { rc.erase(rc.begin() + max_bytes, rc.end()); } + return rc; } -PolymorphicBuffer MakeReferencingBuffer(const void *ptr, std::size_t size) { - return MakeReferencingBuffer(ptr, size, [] {}); +PolymorphicBuffer +MakeReferencingBuffer(const void *ptr, std::size_t size) +{ + return MakeReferencingBuffer(ptr, size, [] {}); } -PolymorphicBuffer MakeForeignBuffer(std::string buffer) { - auto size = buffer.size(); - return PolymorphicBuffer( - MakeRefCounted>(std::move(buffer)), 0, - size); +PolymorphicBuffer +MakeForeignBuffer(std::string buffer) +{ + auto size = buffer.size(); + return PolymorphicBuffer(MakeRefCounted>(std::move(buffer)), 0, size); } -template -PolymorphicBuffer MakeForeignBuffer(std::vector buffer) { - auto size = buffer.size() * sizeof(T); - return PolymorphicBuffer( - MakeRefCounted>>(std::move(buffer)), 0, - size); +template +PolymorphicBuffer +MakeForeignBuffer(std::vector buffer) +{ + auto size = buffer.size() * sizeof(T); + return PolymorphicBuffer(MakeRefCounted>>(std::move(buffer)), 0, size); } -#define TILE_INSTANIATE_MAKE_FOREIGN_BUFFER(type) \ - template PolymorphicBuffer MakeForeignBuffer(std::vector buffer) +#define TILE_INSTANIATE_MAKE_FOREIGN_BUFFER(type) template PolymorphicBuffer MakeForeignBuffer(std::vector buffer) TILE_INSTANIATE_MAKE_FOREIGN_BUFFER(char); TILE_INSTANIATE_MAKE_FOREIGN_BUFFER(signed char); @@ -224,51 +233,50 @@ TILE_INSTANIATE_MAKE_FOREIGN_BUFFER(float); TILE_INSTANIATE_MAKE_FOREIGN_BUFFER(double); TILE_INSTANIATE_MAKE_FOREIGN_BUFFER(long double); -bool StartsWith(NoncontiguousBuffer buffer, Slice prefix) { - if (buffer.ByteSize() < prefix.size()) { - return false; - } +bool +StartsWith(NoncontiguousBuffer buffer, Slice prefix) +{ + if (buffer.ByteSize() < prefix.size()) { return false; } - while (!buffer.Empty() && prefix.empty()) { - auto first = buffer.FirstContiguous(); - auto min_len = std::min(first.size(), prefix.size()); - if (memcmp(first.data(), prefix.data(), min_len) != 0) { - return false; + while (!buffer.Empty() && prefix.empty()) { + auto first = buffer.FirstContiguous(); + auto min_len = std::min(first.size(), prefix.size()); + if (memcmp(first.data(), prefix.data(), min_len) != 0) { return false; } + + buffer.Skip(min_len); + prefix.RemovePrefix(min_len); } - - buffer.Skip(min_len); - prefix.RemovePrefix(min_len); - } - return prefix.empty(); + return prefix.empty(); } -bool EndsWith(NoncontiguousBuffer buffer, Slice suffix) { - TILE_NOT_IMPLEMENTED(""); - return false; -} - -bool StartsWithIgnoreCase(NoncontiguousBuffer buffer, Slice prefix) { - if (buffer.ByteSize() < prefix.size()) { +bool +EndsWith(NoncontiguousBuffer buffer, Slice suffix) +{ + TILE_NOT_IMPLEMENTED(""); return false; - } +} - while (!buffer.Empty() && prefix.empty()) { - auto first = buffer.FirstContiguous(); - auto min_len = std::min(first.size(), prefix.size()); +bool +StartsWithIgnoreCase(NoncontiguousBuffer buffer, Slice prefix) +{ + if (buffer.ByteSize() < prefix.size()) { return false; } - if (!EqualsIgnoreCase(first.substr(0, min_len), - prefix.substr(0, min_len))) { - return false; + while (!buffer.Empty() && prefix.empty()) { + auto first = buffer.FirstContiguous(); + auto min_len = std::min(first.size(), prefix.size()); + + if (!EqualsIgnoreCase(first.substr(0, min_len), prefix.substr(0, min_len))) { return false; } + + buffer.Skip(min_len); + prefix.RemovePrefix(min_len); } - - buffer.Skip(min_len); - prefix.RemovePrefix(min_len); - } - return prefix.empty(); + return prefix.empty(); } -bool EndsWithIgnoreCase(NoncontiguousBuffer buffer, Slice suffix) { - TILE_NOT_IMPLEMENTED(""); +bool +EndsWithIgnoreCase(NoncontiguousBuffer buffer, Slice suffix) +{ + TILE_NOT_IMPLEMENTED(""); } -} // namespace tile +}// namespace tile diff --git a/tile/base/buffer.h b/tile/base/buffer.h index c6a3022..3bf39d3 100644 --- a/tile/base/buffer.h +++ b/tile/base/buffer.h @@ -19,355 +19,376 @@ namespace tile { namespace detail { -template -constexpr auto data(const T &c) - -> enable_if_t::value, - const char *> { - return c.data(); +template +constexpr auto +data(const T &c) -> enable_if_t::value, const char *> +{ + return c.data(); } -template -constexpr auto data(const char (&c)[N]) -> decltype(c) { - return c; +template +constexpr auto +data(const char (&c)[N]) -> decltype(c) +{ + return c; } -template constexpr std::size_t size(const T &c) { - return c.size(); +template +constexpr std::size_t +size(const T &c) +{ + return c.size(); } -template struct size_impl { - static constexpr std::size_t size(const char (&c)[N]) { - return N - (c[N - 1] == '\0'); - } -}; -template <> struct size_impl<0> { - static constexpr std::size_t size(const char (&c)[0]) { return 0; } +template +struct size_impl { + static constexpr std::size_t size(const char (&c)[N]) { return N - (c[N - 1] == '\0'); } }; -template constexpr std::size_t size(const char (&c)[N]) { - return size_impl::size(c); +template<> +struct size_impl<0> { + static constexpr std::size_t size(const char (&c)[0]) { return 0; } +}; + +template +constexpr std::size_t +size(const char (&c)[N]) +{ + return size_impl::size(c); } -template constexpr std::size_t total_size(const A1 &a1) { - return size(a1); +template +constexpr std::size_t +total_size(const A1 &a1) +{ + return size(a1); } -template -constexpr std::size_t total_size(const A1 &a1, const Args &...args) { - return size(a1) + total_size(args...); +template +constexpr std::size_t +total_size(const A1 &a1, const Args &...args) +{ + return size(a1) + total_size(args...); } -} // namespace detail +}// namespace detail class NoncontiguousBuffer { - // - using LinkedBuffers = - internal::SinglyLinkedList; + // + using LinkedBuffers = internal::SinglyLinkedList; public: - using iterator = LinkedBuffers::iterator; - using const_iterator = LinkedBuffers::const_iterator; - using buffer_t = PolymorphicBuffer; + using iterator = LinkedBuffers::iterator; + using const_iterator = LinkedBuffers::const_iterator; + using buffer_t = PolymorphicBuffer; - constexpr NoncontiguousBuffer() = default; + constexpr NoncontiguousBuffer() = default; - // Copyable & moveable - NoncontiguousBuffer(const NoncontiguousBuffer &other); - NoncontiguousBuffer &operator=(const NoncontiguousBuffer &other); - NoncontiguousBuffer(NoncontiguousBuffer &&other) noexcept - : byte_size_(internal::Exchange(other.byte_size_, 0)), - buffers_(std::move(other.buffers_)) {} - NoncontiguousBuffer &operator=(NoncontiguousBuffer &&other) noexcept { - if (TILE_UNLIKELY(&other == this)) { - return *this; + // Copyable & moveable + NoncontiguousBuffer(const NoncontiguousBuffer &other); + NoncontiguousBuffer &operator=(const NoncontiguousBuffer &other); + + NoncontiguousBuffer(NoncontiguousBuffer &&other) noexcept + : byte_size_(internal::Exchange(other.byte_size_, 0)), + buffers_(std::move(other.buffers_)) + {} + + NoncontiguousBuffer &operator=(NoncontiguousBuffer &&other) noexcept + { + if (TILE_UNLIKELY(&other == this)) { return *this; } + + Clear(); + std::swap(byte_size_, other.byte_size_); + buffers_ = std::move(other.buffers_); + return *this; } - Clear(); - std::swap(byte_size_, other.byte_size_); - buffers_ = std::move(other.buffers_); - return *this; - } + ~NoncontiguousBuffer() { Clear(); } - ~NoncontiguousBuffer() { Clear(); } - - Slice FirstContiguous() const noexcept { - TILE_DCHECK(!Empty()); - auto &&first = buffers_.front(); - return Slice(first.data(), first.size()); - } - - void Skip(size_t bytes) noexcept { - TILE_DCHECK_LE(bytes, ByteSize()); - if (TILE_UNLIKELY(bytes == 0)) { - } else if (bytes < buffers_.front().size()) { - buffers_.front().Skip(bytes); - byte_size_ -= bytes; - } else { - SkipSlow(bytes); - } - } - - NoncontiguousBuffer Cut(std::size_t bytes) { - TILE_DCHECK_LE(bytes, ByteSize()); - TILE_DCHECK_GE(bytes, 0); - - NoncontiguousBuffer rc; - auto left = bytes; - while (left && left >= buffers_.front().size()) { - left -= buffers_.front().size(); - rc.buffers_.push_back(buffers_.pop_front()); + Slice FirstContiguous() const noexcept + { + TILE_DCHECK(!Empty()); + auto &&first = buffers_.front(); + return Slice(first.data(), first.size()); } - if (TILE_LIKELY(left > 0)) { - auto ncb = object_pool::Get().Leak(); - *ncb = buffers_.front(); - ncb->set_size(left); - rc.buffers_.push_back(ncb); - buffers_.front().Skip(left); - } - rc.byte_size_ = bytes; - byte_size_ -= bytes; - return rc; - } - - void Append(PolymorphicBuffer buffer) { - if (TILE_UNLIKELY(buffer.size() == 0)) { - return; + void Skip(size_t bytes) noexcept + { + TILE_DCHECK_LE(bytes, ByteSize()); + if (TILE_UNLIKELY(bytes == 0)) { + } else if (bytes < buffers_.front().size()) { + buffers_.front().Skip(bytes); + byte_size_ -= bytes; + } else { + SkipSlow(bytes); + } } - auto block = object_pool::Get(); - *block = std::move(buffer); - byte_size_ += block->size(); - buffers_.push_back(block.Leak()); - } + NoncontiguousBuffer Cut(std::size_t bytes) + { + TILE_DCHECK_LE(bytes, ByteSize()); + TILE_DCHECK_GE(bytes, 0); - void Append(NoncontiguousBuffer buffer) { - byte_size_ += internal::Exchange(buffer.byte_size_, 0); - buffers_.splice(std::move(buffer.buffers_)); - } + NoncontiguousBuffer rc; + auto left = bytes; + while (left && left >= buffers_.front().size()) { + left -= buffers_.front().size(); + rc.buffers_.push_back(buffers_.pop_front()); + } - std::size_t ByteSize() const noexcept { return byte_size_; } - - bool Empty() const noexcept { - TILE_CHECK_EQ(buffers_.empty(), !byte_size_); - return !byte_size_; - } - - void Clear() noexcept { - if (!Empty()) { - ClearSlow(); + if (TILE_LIKELY(left > 0)) { + auto ncb = object_pool::Get().Leak(); + *ncb = buffers_.front(); + ncb->set_size(left); + rc.buffers_.push_back(ncb); + buffers_.front().Skip(left); + } + rc.byte_size_ = bytes; + byte_size_ -= bytes; + return rc; } - } - iterator begin() noexcept { return buffers_.begin(); } - iterator end() noexcept { return buffers_.end(); } - const_iterator begin() const noexcept { return buffers_.begin(); } - const_iterator end() const noexcept { return buffers_.end(); } + void Append(PolymorphicBuffer buffer) + { + if (TILE_UNLIKELY(buffer.size() == 0)) { return; } + + auto block = object_pool::Get(); + *block = std::move(buffer); + byte_size_ += block->size(); + buffers_.push_back(block.Leak()); + } + + void Append(NoncontiguousBuffer buffer) + { + byte_size_ += internal::Exchange(buffer.byte_size_, 0); + buffers_.splice(std::move(buffer.buffers_)); + } + + std::size_t ByteSize() const noexcept { return byte_size_; } + + bool Empty() const noexcept + { + TILE_CHECK_EQ(buffers_.empty(), !byte_size_); + return !byte_size_; + } + + void Clear() noexcept + { + if (!Empty()) { ClearSlow(); } + } + + iterator begin() noexcept { return buffers_.begin(); } + + iterator end() noexcept { return buffers_.end(); } + + const_iterator begin() const noexcept { return buffers_.begin(); } + + const_iterator end() const noexcept { return buffers_.end(); } private: - void SkipSlow(size_t bytes) noexcept; - void ClearSlow() noexcept; + void SkipSlow(size_t bytes) noexcept; + void ClearSlow() noexcept; private: - std::size_t byte_size_{}; - LinkedBuffers buffers_; + std::size_t byte_size_{}; + LinkedBuffers buffers_; }; class NoncontiguousBufferBuilder { - static constexpr auto kAppendViaCopyThreshold = 128; + static constexpr auto kAppendViaCopyThreshold = 128; public: - NoncontiguousBufferBuilder() { InitializeNextBlock(); } + NoncontiguousBufferBuilder() { InitializeNextBlock(); } - // current write ptr - // It's size is available at `SizeAvailable()` - char *data() const noexcept { return current_->mutable_data() + used_; } + // current write ptr + // It's size is available at `SizeAvailable()` + char *data() const noexcept { return current_->mutable_data() + used_; } - std::size_t SizeAvailable() const noexcept { - return current_->size() - used_; - } + std::size_t SizeAvailable() const noexcept { return current_->size() - used_; } - void MarkWritten(std::size_t bytes) { - TILE_DCHECK_LE(bytes, SizeAvailable(), "You're overflowing the buffer."); - used_ += bytes; - // Is fulled ? - if (TILE_UNLIKELY(!SizeAvailable())) { - FlushCurrentBlock(); - InitializeNextBlock(); - } - } - - // Allocate new block - // return write ptr - char *Reserve(std::size_t bytes) { - static const auto kMaxBytes = 1024; - TILE_CHECK_LE(bytes, kMaxBytes, - "At most [{}] bytes may be reserved in single call.", - kMaxBytes); - if (SizeAvailable() < bytes) { - FlushCurrentBlock(); - InitializeNextBlock(); + void MarkWritten(std::size_t bytes) + { + TILE_DCHECK_LE(bytes, SizeAvailable(), "You're overflowing the buffer."); + used_ += bytes; + // Is fulled ? + if (TILE_UNLIKELY(!SizeAvailable())) { + FlushCurrentBlock(); + InitializeNextBlock(); + } } - auto ptr = data(); - MarkWritten(bytes); - return ptr; - } + // Allocate new block + // return write ptr + char *Reserve(std::size_t bytes) + { + static const auto kMaxBytes = 1024; + TILE_CHECK_LE(bytes, kMaxBytes, "At most [{}] bytes may be reserved in single call.", kMaxBytes); + if (SizeAvailable() < bytes) { + FlushCurrentBlock(); + InitializeNextBlock(); + } - // Total number of bytes written - std::size_t ByteSize() const noexcept { return nb_.ByteSize() + used_; } - - NoncontiguousBuffer DestructiveGet() noexcept { - FlushCurrentBlock(); - return std::move(nb_); - } - - void Append(const void *ptr, std::size_t length) { - auto current = data(); - used_ += length; - if (TILE_LIKELY(used_ < current_->size())) { - memcpy(static_cast(current), ptr, length); - return; - } - used_ -= length; - AppendSlow(ptr, length); - } - - void Append(Slice s) { return Append(s.data(), s.size()); } - - void Append(const std::string &s) { Append(s.data(), s.size()); } - - void Append(PolymorphicBuffer buffer) { - if (buffer.size() < kAppendViaCopyThreshold && - SizeAvailable() >= buffer.size()) { - Append(buffer.data(), buffer.size()); - return; + auto ptr = data(); + MarkWritten(bytes); + return ptr; } - if (used_) { - FlushCurrentBlock(); - InitializeNextBlock(); + // Total number of bytes written + std::size_t ByteSize() const noexcept { return nb_.ByteSize() + used_; } + + NoncontiguousBuffer DestructiveGet() noexcept + { + FlushCurrentBlock(); + return std::move(nb_); } - nb_.Append(std::move(buffer)); - } - - void Append(NoncontiguousBuffer buffer) { - if (buffer.ByteSize() < kAppendViaCopyThreshold && SizeAvailable()) { - AppendCopy(buffer); - return; + void Append(const void *ptr, std::size_t length) + { + auto current = data(); + used_ += length; + if (TILE_LIKELY(used_ < current_->size())) { + memcpy(static_cast(current), ptr, length); + return; + } + used_ -= length; + AppendSlow(ptr, length); } - if (used_) { - FlushCurrentBlock(); - InitializeNextBlock(); + void Append(Slice s) { return Append(s.data(), s.size()); } + + void Append(const std::string &s) { Append(s.data(), s.size()); } + + void Append(PolymorphicBuffer buffer) + { + if (buffer.size() < kAppendViaCopyThreshold && SizeAvailable() >= buffer.size()) { + Append(buffer.data(), buffer.size()); + return; + } + + if (used_) { + FlushCurrentBlock(); + InitializeNextBlock(); + } + + nb_.Append(std::move(buffer)); } - nb_.Append(std::move(buffer)); - } - void Append(char c) { Append(static_cast(c)); } + void Append(NoncontiguousBuffer buffer) + { + if (buffer.ByteSize() < kAppendViaCopyThreshold && SizeAvailable()) { + AppendCopy(buffer); + return; + } - void Append(unsigned char c) { - TILE_DCHECK(SizeAvailable()); - *reinterpret_cast(data()) = c; - MarkWritten(1); - } - - template < - typename... Ts, - typename = - internal::void_t()))...>, - typename = - internal::void_t()))...>> - void Append(const Ts &...buffers) { - auto current = data(); - auto total = detail::total_size(buffers...); - used_ += total; - if (TILE_LIKELY(used_ < current_->size())) { - UncheckedAppend(current, buffers...); - return; + if (used_) { + FlushCurrentBlock(); + InitializeNextBlock(); + } + nb_.Append(std::move(buffer)); } - used_ -= total; - int dummy[] = {(Append(buffers), 0)...}; - } - template - auto Append(T) -> enable_if_t::value> { - static_assert(sizeof(T) == 0, "Please use Append(char) instead."); - } + void Append(char c) { Append(static_cast(c)); } + + void Append(unsigned char c) + { + TILE_DCHECK(SizeAvailable()); + *reinterpret_cast(data()) = c; + MarkWritten(1); + } + + template()))...>, + typename = internal::void_t()))...>> + void Append(const Ts &...buffers) + { + auto current = data(); + auto total = detail::total_size(buffers...); + used_ += total; + if (TILE_LIKELY(used_ < current_->size())) { + UncheckedAppend(current, buffers...); + return; + } + used_ -= total; + int dummy[] = {(Append(buffers), 0)...}; + } + + template + auto Append(T) -> enable_if_t::value> + { + static_assert(sizeof(T) == 0, "Please use Append(char) instead."); + } private: - // Allocate a new buffer - void InitializeNextBlock(); + // Allocate a new buffer + void InitializeNextBlock(); - void FlushCurrentBlock(); + void FlushCurrentBlock(); - void AppendSlow(const void *ptr, std::size_t length); - void AppendCopy(const NoncontiguousBuffer &buffer); + void AppendSlow(const void *ptr, std::size_t length); + void AppendCopy(const NoncontiguousBuffer &buffer); - template - inline void UncheckedAppend(char *ptr, const T &slice) { - memcpy(ptr, detail::data(slice), detail::size(slice)); - } + template + inline void UncheckedAppend(char *ptr, const T &slice) + { + memcpy(ptr, detail::data(slice), detail::size(slice)); + } - template - inline void UncheckedAppend(char *ptr, const T &slice, const Ts &...slices) { - memcpy(ptr, detail::data(slice), detail::size(slice)); - UncheckedAppend(ptr + detail::size(slice), slices...); - } + template + inline void UncheckedAppend(char *ptr, const T &slice, const Ts &...slices) + { + memcpy(ptr, detail::data(slice), detail::size(slice)); + UncheckedAppend(ptr + detail::size(slice), slices...); + } private: - NoncontiguousBuffer nb_; - std::size_t used_; - RefPtr current_; + NoncontiguousBuffer nb_; + std::size_t used_; + RefPtr current_; }; namespace detail { -void FlattenToSlowSlow(const NoncontiguousBuffer &ncb, void *buffer, - std::size_t size); +void FlattenToSlowSlow(const NoncontiguousBuffer &ncb, void *buffer, std::size_t size); } NoncontiguousBuffer CreateBufferSlow(Slice s); NoncontiguousBuffer CreateBufferSlow(const void *ptr, std::size_t size); -std::string -FlattenSlow(const NoncontiguousBuffer &nb, - std::size_t max_bytes = std::numeric_limits::max()); -std::string FlattenSlowUntil( - const NoncontiguousBuffer &nb, Slice delim, - std::size_t max_bytes = std::numeric_limits::max()); -inline void FlattenToSlow(const NoncontiguousBuffer &nb, void *buffer, - std::size_t max_bytes) { - if (TILE_LIKELY(max_bytes <= nb.FirstContiguous().size())) { - std::memcpy(buffer, nb.FirstContiguous().data(), max_bytes); - } - return detail::FlattenToSlowSlow(nb, buffer, max_bytes); +std::string FlattenSlow(const NoncontiguousBuffer &nb, std::size_t max_bytes = std::numeric_limits::max()); +std::string FlattenSlowUntil(const NoncontiguousBuffer &nb, + Slice delim, + std::size_t max_bytes = std::numeric_limits::max()); + +inline void +FlattenToSlow(const NoncontiguousBuffer &nb, void *buffer, std::size_t max_bytes) +{ + if (TILE_LIKELY(max_bytes <= nb.FirstContiguous().size())) { + std::memcpy(buffer, nb.FirstContiguous().data(), max_bytes); + } + return detail::FlattenToSlowSlow(nb, buffer, max_bytes); } PolymorphicBuffer MakeReferencingBuffer(const void *ptr, std::size_t size); -template -PolymorphicBuffer MakeReferencingBuffer(const void *ptr, std::size_t size, - F &&completion_cb) { - using BufferBlock = - ReferencingBufferBlock::type>; - return PolymorphicBuffer( - MakeRefCounted( - ptr, size, - std::forward::type>(completion_cb)), - 0, size); +template +PolymorphicBuffer +MakeReferencingBuffer(const void *ptr, std::size_t size, F &&completion_cb) +{ + using BufferBlock = ReferencingBufferBlock::type>; + return PolymorphicBuffer( + MakeRefCounted(ptr, size, std::forward::type>(completion_cb)), 0, + size); } PolymorphicBuffer MakeForeignBuffer(std::string buffer); // `T` in (`std::byte`, integral types, floating types) -template +template PolymorphicBuffer MakeForeignBuffer(std::vector buffer); bool StartsWith(NoncontiguousBuffer buffer, Slice prefix); bool EndsWith(NoncontiguousBuffer buffer, Slice suffix); bool StartsWithIgnoreCase(NoncontiguousBuffer buffer, Slice prefix); bool EndsWithIgnoreCase(NoncontiguousBuffer buffer, Slice suffix); -} // namespace tile +}// namespace tile -#endif // TILE_BASE_BUFFER_H +#endif// TILE_BASE_BUFFER_H diff --git a/tile/base/buffer/builtin_buffer_block.cc b/tile/base/buffer/builtin_buffer_block.cc index 8b1054a..29c76d1 100644 --- a/tile/base/buffer/builtin_buffer_block.cc +++ b/tile/base/buffer/builtin_buffer_block.cc @@ -19,104 +19,108 @@ namespace tile { namespace { -template -struct alignas(hardware_destructive_interference_size) FixedNativeBufferBlock - : NativeBufferBlock { +template +struct alignas(hardware_destructive_interference_size) FixedNativeBufferBlock : NativeBufferBlock { public: - static RefPtr New() { - // WARNING: don't use adopt_ptr - return RefPtr>( - adopt_ptr, object_pool::Get>().Leak()); - } + static RefPtr New() + { + // WARNING: don't use adopt_ptr + return RefPtr>( + adopt_ptr, object_pool::Get>().Leak()); + } - // HACK: add ref ensure `RefCount`. - static void Delete(FixedNativeBufferBlock *ptr) { - ptr->Save(); - object_pool::Put>(ptr); - } + // HACK: add ref ensure `RefCount`. + static void Delete(FixedNativeBufferBlock *ptr) + { + ptr->Save(); + object_pool::Put>(ptr); + } - char *mutable_data() noexcept override { return buffer.data(); } - const char *data() const noexcept override { return buffer.data(); } - std::size_t size() const noexcept override { return buffer.size(); } - void Destroy() noexcept override { Delete(this); } + char *mutable_data() noexcept override { return buffer.data(); } - static constexpr std::size_t kBufferSize = kSize - sizeof(NativeBufferBlock); - std::array buffer; + const char *data() const noexcept override { return buffer.data(); } + + std::size_t size() const noexcept override { return buffer.size(); } + + void Destroy() noexcept override { Delete(this); } + + static constexpr std::size_t kBufferSize = kSize - sizeof(NativeBufferBlock); + std::array buffer; }; -template -RefPtr MakeNativeBufferBlockOfBytes() { - return FixedNativeBufferBlock::New(); +template +RefPtr +MakeNativeBufferBlockOfBytes() +{ + return FixedNativeBufferBlock::New(); } -RefPtr (*make_native_buffer_block)() = - MakeNativeBufferBlockOfBytes; +RefPtr (*make_native_buffer_block)() = MakeNativeBufferBlockOfBytes; -void InitializeMakeNativeBufferBlock() { - static const std::unordered_map (*)()> - kMakers = {{"4K", MakeNativeBufferBlockOfBytes}, - {"64K", MakeNativeBufferBlockOfBytes}, - {"1M", MakeNativeBufferBlockOfBytes} - - }; - auto iter = kMakers.find(FLAGS_tile_buffer_block_size); - if (iter != kMakers.end()) { - make_native_buffer_block = iter->second; - } else { - TILE_UNEXPECTED( - "Unexpected buffer block size [{}]. Only 4K/64K/1M buffer block " - "is supported.", - FLAGS_tile_buffer_block_size); - } +void +InitializeMakeNativeBufferBlock() +{ + static const std::unordered_map (*)()> kMakers = { + {"4K", MakeNativeBufferBlockOfBytes }, + {"64K", MakeNativeBufferBlockOfBytes}, + {"1M", MakeNativeBufferBlockOfBytes } + }; + auto iter = kMakers.find(FLAGS_tile_buffer_block_size); + if (iter != kMakers.end()) { + make_native_buffer_block = iter->second; + } else { + TILE_UNEXPECTED("Unexpected buffer block size [{}]. Only 4K/64K/1M buffer block " + "is supported.", + FLAGS_tile_buffer_block_size); + } } TILE_ON_INIT(0, InitializeMakeNativeBufferBlock); -} // namespace +}// namespace -RefPtr MakeNativeBufferBlock() { - return make_native_buffer_block(); +RefPtr +MakeNativeBufferBlock() +{ + return make_native_buffer_block(); } -template <> struct PoolTraits> { - static constexpr auto kType = PoolType::MemoryNodeShared; - static constexpr auto kLowWaterMark = 16384; // 64M per node. - static constexpr auto kHighWaterMark = - std::numeric_limits::max(); - static constexpr auto kMaxIdle = std::chrono::seconds(10); - static constexpr auto kMinimumThreadCacheSize = 4096; // 16M per thread. - static constexpr auto kTransferBatchSize = 1024; // Extra 4M. +template<> +struct PoolTraits> { + static constexpr auto kType = PoolType::MemoryNodeShared; + static constexpr auto kLowWaterMark = 16384;// 64M per node. + static constexpr auto kHighWaterMark = std::numeric_limits::max(); + static constexpr auto kMaxIdle = std::chrono::seconds(10); + static constexpr auto kMinimumThreadCacheSize = 4096;// 16M per thread. + static constexpr auto kTransferBatchSize = 1024;// Extra 4M. }; -template <> struct PoolTraits> { - static constexpr auto kType = PoolType::MemoryNodeShared; - static constexpr auto kLowWaterMark = 1024; // 64M per node. - static constexpr auto kHighWaterMark = - std::numeric_limits::max(); - static constexpr auto kMaxIdle = std::chrono::seconds(10); - static constexpr auto kMinimumThreadCacheSize = 256; // 16M per thread. - static constexpr auto kTransferBatchSize = 64; // Extra 4M. +template<> +struct PoolTraits> { + static constexpr auto kType = PoolType::MemoryNodeShared; + static constexpr auto kLowWaterMark = 1024;// 64M per node. + static constexpr auto kHighWaterMark = std::numeric_limits::max(); + static constexpr auto kMaxIdle = std::chrono::seconds(10); + static constexpr auto kMinimumThreadCacheSize = 256;// 16M per thread. + static constexpr auto kTransferBatchSize = 64; // Extra 4M. }; -template <> struct PoolTraits> { - static constexpr auto kType = PoolType::MemoryNodeShared; - static constexpr auto kLowWaterMark = 128; // 128M per node. - static constexpr auto kHighWaterMark = - std::numeric_limits::max(); - static constexpr auto kMaxIdle = std::chrono::seconds(10); - static constexpr auto kMinimumThreadCacheSize = 64; // 64M per thread. - static constexpr auto kTransferBatchSize = 16; // Extra 16M. +template<> +struct PoolTraits> { + static constexpr auto kType = PoolType::MemoryNodeShared; + static constexpr auto kLowWaterMark = 128;// 128M per node. + static constexpr auto kHighWaterMark = std::numeric_limits::max(); + static constexpr auto kMaxIdle = std::chrono::seconds(10); + static constexpr auto kMinimumThreadCacheSize = 64;// 64M per thread. + static constexpr auto kTransferBatchSize = 16;// Extra 16M. }; constexpr PoolType PoolTraits>::kType; constexpr PoolType PoolTraits>::kType; constexpr PoolType PoolTraits>::kType; -constexpr std::chrono::seconds - PoolTraits>::kMaxIdle; -constexpr std::chrono::seconds - PoolTraits>::kMaxIdle; -constexpr std::chrono::seconds - PoolTraits>::kMaxIdle; +constexpr std::chrono::seconds PoolTraits>::kMaxIdle; +constexpr std::chrono::seconds PoolTraits>::kMaxIdle; +constexpr std::chrono::seconds PoolTraits>::kMaxIdle; -} // namespace tile +}// namespace tile diff --git a/tile/base/buffer/builtin_buffer_block.h b/tile/base/buffer/builtin_buffer_block.h index ef4480b..484b3ea 100644 --- a/tile/base/buffer/builtin_buffer_block.h +++ b/tile/base/buffer/builtin_buffer_block.h @@ -8,34 +8,32 @@ #include "tile/base/ref_ptr.h" namespace tile { -class alignas(hardware_destructive_interference_size) NativeBufferBlock - : public PolymorphicBufferBlock { +class alignas(hardware_destructive_interference_size) NativeBufferBlock : public PolymorphicBufferBlock { public: - virtual char *mutable_data() noexcept = 0; + virtual char *mutable_data() noexcept = 0; }; RefPtr MakeNativeBufferBlock(); -template -class ReferencingBufferBlock : public PolymorphicBufferBlock, - private F /* Empty Base Optimize */ { +template +class ReferencingBufferBlock : public PolymorphicBufferBlock, private F /* Empty Base Optimize */ { public: - explicit ReferencingBufferBlock(const void *ptr, std::size_t size, - F &&completion_cb) - : F(std::move(completion_cb)), ptr_(ptr), size_(size) {} + explicit ReferencingBufferBlock(const void *ptr, std::size_t size, F &&completion_cb) + : F(std::move(completion_cb)), + ptr_(ptr), + size_(size) + {} - ~ReferencingBufferBlock() override { (*this)(); } + ~ReferencingBufferBlock() override { (*this)(); } - const char *data() const noexcept override { - return reinterpret_cast(ptr_); - } + const char *data() const noexcept override { return reinterpret_cast(ptr_); } - std::size_t size() const noexcept override { return size_; } + std::size_t size() const noexcept override { return size_; } private: - const void *ptr_; - std::size_t size_; -}; // namespace tile -} // namespace tile + const void *ptr_; + std::size_t size_; +};// namespace tile +}// namespace tile -#endif // TILE_BASE_BUFFER_BUILTIN_BUFFER_BLOCK_H +#endif// TILE_BASE_BUFFER_BUILTIN_BUFFER_BLOCK_H diff --git a/tile/base/buffer/circular_buffer.h b/tile/base/buffer/circular_buffer.h index a35746d..9a55aad 100644 --- a/tile/base/buffer/circular_buffer.h +++ b/tile/base/buffer/circular_buffer.h @@ -9,59 +9,63 @@ #include namespace tile { -template class CircularBuffer { - class UninitializedObject; +template +class CircularBuffer { + class UninitializedObject; public: - explicit CircularBuffer(std::size_t capacity); + explicit CircularBuffer(std::size_t capacity); - template bool Emplace(Ts &&...args) { - auto head = head_.load(std::memory_order_relaxed); - auto next = NormalizeIndex(head + 1); + template + bool Emplace(Ts &&...args) + { + auto head = head_.load(std::memory_order_relaxed); + auto next = NormalizeIndex(head + 1); - if (next == tail_.load(std::memory_order_acquire)) { - return false; + if (next == tail_.load(std::memory_order_acquire)) { return false; } + + objects_[head].Initialize(std::forward(args)...); + head_.store(next, std::memory_order_release); + return true; } - objects_[head].Initialize(std::forward(args)...); - head_.store(next, std::memory_order_release); - return true; - } + void Pop(std::vector *objects) + { + auto upto = head_.load(std::memory_order_acquire); + auto current = tail_.load(std::memory_order_relaxed); + while (current != upto) { + objects->push_back(std::move(*objects_[current].Get())); + objects_[current].Destroy(); + current = NormalizeIndex(current + 1); + } - void Pop(std::vector *objects) { - auto upto = head_.load(std::memory_order_acquire); - auto current = tail_.load(std::memory_order_relaxed); - while (current != upto) { - objects->push_back(std::move(*objects_[current].Get())); - objects_[current].Destroy(); - current = NormalizeIndex(current + 1); + tail_.store(current, std::memory_order_release); } - tail_.store(current, std::memory_order_release); - } - private: - class UninitializedObject { - public: - T *Get() noexcept { return reinterpret_cast(&storage_); } - template void Initialize(Ts &&...args) { - new (Get()) T(std::forward(args)...); - } + class UninitializedObject { + public: + T *Get() noexcept { return reinterpret_cast(&storage_); } - void Destroy() { Get()->~T(); } + template + void Initialize(Ts &&...args) + { + new (Get()) T(std::forward(args)...); + } - private: - std::aligned_storage storage_; - }; - std::size_t NormalizeIndex(std::size_t x) { - return (x < capacity_) ? x : x - capacity_; - } + void Destroy() { Get()->~T(); } + + private: + std::aligned_storage storage_; + }; + + std::size_t NormalizeIndex(std::size_t x) { return (x < capacity_) ? x : x - capacity_; } private: - std::size_t capacity_; - std::unique_ptr objects_; - std::atomic head_{}, tail_{}; + std::size_t capacity_; + std::unique_ptr objects_; + std::atomic head_{}, tail_{}; }; -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_BUFFER_CIRCULAR_BUFFER_H +#endif// _TILE_BASE_BUFFER_CIRCULAR_BUFFER_H diff --git a/tile/base/buffer/compression_output_stream.cc b/tile/base/buffer/compression_output_stream.cc index 3bafc42..798aeed 100644 --- a/tile/base/buffer/compression_output_stream.cc +++ b/tile/base/buffer/compression_output_stream.cc @@ -2,42 +2,39 @@ namespace tile { -NoncontiguousBufferCompressionOutputStream:: - NoncontiguousBufferCompressionOutputStream( - NoncontiguousBufferBuilder *builder) - : builder_(builder) {} +NoncontiguousBufferCompressionOutputStream::NoncontiguousBufferCompressionOutputStream( + NoncontiguousBufferBuilder *builder) + : builder_(builder) +{} -NoncontiguousBufferCompressionOutputStream:: - ~NoncontiguousBufferCompressionOutputStream() { - Flush(); +NoncontiguousBufferCompressionOutputStream::~NoncontiguousBufferCompressionOutputStream() { Flush(); } + +void +NoncontiguousBufferCompressionOutputStream::Flush() +{ + if (using_bytes_ > 0) { + builder_->MarkWritten(using_bytes_); + using_bytes_ = 0; + } } -void NoncontiguousBufferCompressionOutputStream::Flush() { - if (using_bytes_ > 0) { - builder_->MarkWritten(using_bytes_); - using_bytes_ = 0; - } +bool +NoncontiguousBufferCompressionOutputStream::Next(void **data, std::size_t *size) noexcept +{ + if (!builder_) { return false; } + + if (using_bytes_) { builder_->MarkWritten(using_bytes_); } + + *data = builder_->data(); + *size = builder_->SizeAvailable(); + using_bytes_ = *size; + TILE_CHECK(*size > 0); + return true; } -bool NoncontiguousBufferCompressionOutputStream::Next( - void **data, std::size_t *size) noexcept { - if (!builder_) { - return false; - } - - if (using_bytes_) { - builder_->MarkWritten(using_bytes_); - } - - *data = builder_->data(); - *size = builder_->SizeAvailable(); - using_bytes_ = *size; - TILE_CHECK(*size > 0); - return true; +void +NoncontiguousBufferCompressionOutputStream::BackUp(std::size_t count) noexcept +{ + using_bytes_ -= count; } - -void NoncontiguousBufferCompressionOutputStream::BackUp( - std::size_t count) noexcept { - using_bytes_ -= count; -} -} // namespace tile +}// namespace tile diff --git a/tile/base/buffer/compression_output_stream.h b/tile/base/buffer/compression_output_stream.h index 7a8b090..244f130 100644 --- a/tile/base/buffer/compression_output_stream.h +++ b/tile/base/buffer/compression_output_stream.h @@ -6,22 +6,20 @@ #include "tile/base/compression/compression.h" namespace tile { -class NoncontiguousBufferCompressionOutputStream - : public CompressionOutputStream { +class NoncontiguousBufferCompressionOutputStream : public CompressionOutputStream { public: - explicit NoncontiguousBufferCompressionOutputStream( - NoncontiguousBufferBuilder *builder); - ~NoncontiguousBufferCompressionOutputStream() override; + explicit NoncontiguousBufferCompressionOutputStream(NoncontiguousBufferBuilder *builder); + ~NoncontiguousBufferCompressionOutputStream() override; - void Flush(); + void Flush(); - bool Next(void **data, std::size_t *size) noexcept override; - void BackUp(std::size_t count) noexcept override; + bool Next(void **data, std::size_t *size) noexcept override; + void BackUp(std::size_t count) noexcept override; private: - std::size_t using_bytes_{}; - NoncontiguousBufferBuilder *builder_; + std::size_t using_bytes_{}; + NoncontiguousBufferBuilder *builder_; }; -} // namespace tile +}// namespace tile -#endif // TILE_BASE_BUFFER_COMPRESSION_OUTPUT_STREAM_H +#endif// TILE_BASE_BUFFER_COMPRESSION_OUTPUT_STREAM_H diff --git a/tile/base/buffer/polymorphic_buffer.cc b/tile/base/buffer/polymorphic_buffer.cc index 0476644..663f629 100644 --- a/tile/base/buffer/polymorphic_buffer.cc +++ b/tile/base/buffer/polymorphic_buffer.cc @@ -8,14 +8,18 @@ constexpr std::chrono::seconds PoolTraits::kMaxIdle; constexpr std::size_t PoolTraits::kMinimumThreadCacheSize; constexpr std::size_t PoolTraits::kTransferBatchSize; -void PoolTraits::OnPut(PolymorphicBuffer *bb) { - bb->Clear(); +void +PoolTraits::OnPut(PolymorphicBuffer *bb) +{ + bb->Clear(); } namespace detail { -void PolymorphicBufferBlockDeleter ::operator()(PolymorphicBufferBlock *p) { - TILE_DCHECK_EQ(p->UnsafeRefCount(), 0); - p->Destroy(); +void +PolymorphicBufferBlockDeleter ::operator()(PolymorphicBufferBlock *p) +{ + TILE_DCHECK_EQ(p->UnsafeRefCount(), 0); + p->Destroy(); } -} // namespace detail -} // namespace tile +}// namespace detail +}// namespace tile diff --git a/tile/base/buffer/polymorphic_buffer.h b/tile/base/buffer/polymorphic_buffer.h index ec8547e..18b3840 100644 --- a/tile/base/buffer/polymorphic_buffer.h +++ b/tile/base/buffer/polymorphic_buffer.h @@ -19,102 +19,111 @@ namespace detail { struct PolymorphicBufferBlockDeleter; } -class PolymorphicBufferBlock - : public RefCounted { +class PolymorphicBufferBlock : public RefCounted { public: - virtual ~PolymorphicBufferBlock() = default; - virtual const char *data() const noexcept = 0; - virtual std::size_t size() const noexcept = 0; - virtual void Destroy() noexcept { delete this; } + virtual ~PolymorphicBufferBlock() = default; + virtual const char *data() const noexcept = 0; + virtual std::size_t size() const noexcept = 0; + + virtual void Destroy() noexcept { delete this; } }; -static_assert(!std::is_same, - PolymorphicBufferBlock>::value, - ""); -static_assert(detail::is_default_ref_traits_safe::value, - ""); +static_assert(!std::is_same, PolymorphicBufferBlock>::value, ""); +static_assert(detail::is_default_ref_traits_safe::value, ""); + class PolymorphicBuffer { public: - PolymorphicBuffer() = default; - PolymorphicBuffer(const PolymorphicBuffer &) = default; - PolymorphicBuffer &operator=(const PolymorphicBuffer &) = default; + PolymorphicBuffer() = default; + PolymorphicBuffer(const PolymorphicBuffer &) = default; + PolymorphicBuffer &operator=(const PolymorphicBuffer &) = default; - PolymorphicBuffer(PolymorphicBuffer &&other) noexcept - : ptr_(other.ptr_), size_(other.size_), ref_(std::move(other.ref_)) { - other.Clear(); - } - PolymorphicBuffer &operator=(PolymorphicBuffer &&other) noexcept { - if (this != &other) { - ptr_ = other.ptr_; - size_ = other.size_; - ref_ = other.ref_; - other.Clear(); + PolymorphicBuffer(PolymorphicBuffer &&other) noexcept + : ptr_(other.ptr_), + size_(other.size_), + ref_(std::move(other.ref_)) + { + other.Clear(); } - return *this; - } - PolymorphicBuffer(RefPtr data, std::size_t start, - std::size_t size) - : ptr_(data->data() + start), size_(size), ref_(std::move(data)) {} + PolymorphicBuffer &operator=(PolymorphicBuffer &&other) noexcept + { + if (this != &other) { + ptr_ = other.ptr_; + size_ = other.size_; + ref_ = other.ref_; + other.Clear(); + } + return *this; + } - const char *data() const noexcept { return ptr_; } - std::size_t size() const noexcept { return size_; } + PolymorphicBuffer(RefPtr data, std::size_t start, std::size_t size) + : ptr_(data->data() + start), + size_(size), + ref_(std::move(data)) + {} - void Skip(std::size_t bytes) { - TILE_CHECK_LT(bytes, size_); - size_ -= bytes; - ptr_ += bytes; - } + const char *data() const noexcept { return ptr_; } - void set_size(std::size_t size) { - TILE_DCHECK_LE(size, size_); - size_ = size; - } + std::size_t size() const noexcept { return size_; } - void Reset(RefPtr data, std::size_t start, - std::size_t size) { - TILE_DCHECK_LE(start, size); - TILE_DCHECK_LE(size, data->size()); + void Skip(std::size_t bytes) + { + TILE_CHECK_LT(bytes, size_); + size_ -= bytes; + ptr_ += bytes; + } - ref_ = std::move(data); - ptr_ = data->data() + start; - size_ = size; - } + void set_size(std::size_t size) + { + TILE_DCHECK_LE(size, size_); + size_ = size; + } - void Clear() { - ptr_ = nullptr; - size_ = 0; - ref_ = nullptr; - } + void Reset(RefPtr data, std::size_t start, std::size_t size) + { + TILE_DCHECK_LE(start, size); + TILE_DCHECK_LE(size, data->size()); + + ref_ = std::move(data); + ptr_ = data->data() + start; + size_ = size; + } + + void Clear() + { + ptr_ = nullptr; + size_ = 0; + ref_ = nullptr; + } private: - friend class NoncontiguousBuffer; + friend class NoncontiguousBuffer; - internal::SinglyLinkedListEntry chain; - const char *ptr_{}; - std::size_t size_{}; - RefPtr ref_; + internal::SinglyLinkedListEntry chain; + const char *ptr_{}; + std::size_t size_{}; + RefPtr ref_; }; + namespace detail { struct PolymorphicBufferBlockDeleter { - void operator()(PolymorphicBufferBlock *p); + void operator()(PolymorphicBufferBlock *p); }; -} // namespace detail +}// namespace detail -} // namespace tile +}// namespace tile namespace tile { -template <> struct PoolTraits { - static constexpr auto kType = PoolType::MemoryNodeShared; - static constexpr std::size_t kLowWaterMark = 32768; - static constexpr std::size_t kHighWaterMark = - std::numeric_limits::max(); - static constexpr std::chrono::seconds kMaxIdle = std::chrono::seconds(10); - static constexpr std::size_t kMinimumThreadCacheSize = 8192; - static constexpr std::size_t kTransferBatchSize = 1024; +template<> +struct PoolTraits { + static constexpr auto kType = PoolType::MemoryNodeShared; + static constexpr std::size_t kLowWaterMark = 32768; + static constexpr std::size_t kHighWaterMark = std::numeric_limits::max(); + static constexpr std::chrono::seconds kMaxIdle = std::chrono::seconds(10); + static constexpr std::size_t kMinimumThreadCacheSize = 8192; + static constexpr std::size_t kTransferBatchSize = 1024; - static void OnPut(PolymorphicBuffer *bb); + static void OnPut(PolymorphicBuffer *bb); }; -} // namespace tile -#endif // TILE_BASE_BUFFER_POLYMORPHIC_BUFFER_H +}// namespace tile +#endif// TILE_BASE_BUFFER_POLYMORPHIC_BUFFER_H diff --git a/tile/base/buffer_test.cc b/tile/base/buffer_test.cc index c972a9c..ddc1a0e 100644 --- a/tile/base/buffer_test.cc +++ b/tile/base/buffer_test.cc @@ -14,280 +14,308 @@ namespace tile { namespace { -PolymorphicBuffer MakeNativeBuffer(Slice s) { - auto buffer = MakeNativeBufferBlock(); - memcpy(buffer->mutable_data(), s.data(), s.size()); - return PolymorphicBuffer(buffer, 0, s.size()); +PolymorphicBuffer +MakeNativeBuffer(Slice s) +{ + auto buffer = MakeNativeBufferBlock(); + memcpy(buffer->mutable_data(), s.data(), s.size()); + return PolymorphicBuffer(buffer, 0, s.size()); } -} // namespace +}// namespace -TEST(CreateBufferSlow, All) { - static const auto kData = Slice("sadfas234sadf-/+8sdaf sd f~!#"); - auto nb = CreateBufferSlow(kData); - ASSERT_EQ(kData, nb.FirstContiguous().data()); - ASSERT_EQ(kData, FlattenSlow(nb)); +TEST(CreateBufferSlow, All) +{ + static const auto kData = Slice("sadfas234sadf-/+8sdaf sd f~!#"); + auto nb = CreateBufferSlow(kData); + ASSERT_EQ(kData, nb.FirstContiguous().data()); + ASSERT_EQ(kData, FlattenSlow(nb)); } -TEST(NoncontiguousBuffer, Cut) { - NoncontiguousBuffer nb; - nb.Append(CreateBufferSlow("asdf")); - auto r = nb.Cut(3); - ASSERT_EQ(1, nb.ByteSize()); - ASSERT_EQ("f", FlattenSlow(nb)); - ASSERT_EQ(3, r.ByteSize()); - ASSERT_EQ("asd", FlattenSlow(r)); +TEST(NoncontiguousBuffer, Cut) +{ + NoncontiguousBuffer nb; + nb.Append(CreateBufferSlow("asdf")); + auto r = nb.Cut(3); + ASSERT_EQ(1, nb.ByteSize()); + ASSERT_EQ("f", FlattenSlow(nb)); + ASSERT_EQ(3, r.ByteSize()); + ASSERT_EQ("asd", FlattenSlow(r)); } -TEST(NoncontiguousBuffer, Cut1) { - NoncontiguousBuffer nb; - nb.Append(CreateBufferSlow("asdf")); - auto r = nb.Cut(4); - ASSERT_TRUE(nb.Empty()); - ASSERT_EQ(4, r.ByteSize()); +TEST(NoncontiguousBuffer, Cut1) +{ + NoncontiguousBuffer nb; + nb.Append(CreateBufferSlow("asdf")); + auto r = nb.Cut(4); + ASSERT_TRUE(nb.Empty()); + ASSERT_EQ(4, r.ByteSize()); } -TEST(NoncontiguousBuffer, Cut2) { - NoncontiguousBuffer nb; - nb.Append(MakeNativeBuffer("asdf")); - nb.Append(MakeNativeBuffer("asdf")); - auto r = nb.Cut(4); - ASSERT_EQ(4, nb.ByteSize()); - ASSERT_EQ(4, r.ByteSize()); +TEST(NoncontiguousBuffer, Cut2) +{ + NoncontiguousBuffer nb; + nb.Append(MakeNativeBuffer("asdf")); + nb.Append(MakeNativeBuffer("asdf")); + auto r = nb.Cut(4); + ASSERT_EQ(4, nb.ByteSize()); + ASSERT_EQ(4, r.ByteSize()); } -TEST(NoncontiguousBuffer, Cut3) { - NoncontiguousBuffer nb; - nb.Append(MakeNativeBuffer("asdf")); - nb.Append(MakeNativeBuffer("asdf")); - auto r = nb.Cut(8); - ASSERT_TRUE(nb.Empty()); - ASSERT_EQ(8, r.ByteSize()); +TEST(NoncontiguousBuffer, Cut3) +{ + NoncontiguousBuffer nb; + nb.Append(MakeNativeBuffer("asdf")); + nb.Append(MakeNativeBuffer("asdf")); + auto r = nb.Cut(8); + ASSERT_TRUE(nb.Empty()); + ASSERT_EQ(8, r.ByteSize()); } -TEST(NoncontiguousBuffer, Cut4) { - auto nb = CreateBufferSlow("asdfasf2345sfsdfdf"); - auto nb2 = nb; - ASSERT_EQ(FlattenSlow(nb), FlattenSlow(nb2)); - NoncontiguousBuffer splited; - splited.Append(nb.Cut(1)); - splited.Append(nb.Cut(2)); - splited.Append(nb.Cut(3)); - splited.Append(nb.Cut(4)); - splited.Append(std::move(nb)); - ASSERT_EQ(FlattenSlow(nb2), FlattenSlow(splited)); +TEST(NoncontiguousBuffer, Cut4) +{ + auto nb = CreateBufferSlow("asdfasf2345sfsdfdf"); + auto nb2 = nb; + ASSERT_EQ(FlattenSlow(nb), FlattenSlow(nb2)); + NoncontiguousBuffer splited; + splited.Append(nb.Cut(1)); + splited.Append(nb.Cut(2)); + splited.Append(nb.Cut(3)); + splited.Append(nb.Cut(4)); + splited.Append(std::move(nb)); + ASSERT_EQ(FlattenSlow(nb2), FlattenSlow(splited)); } -TEST(NoncontiguousBuffer, Skip) { - NoncontiguousBuffer splited; - splited.Append(CreateBufferSlow("asdf")); - splited.Append(CreateBufferSlow("asdf")); - splited.Append(CreateBufferSlow("asdf")); - splited.Append(CreateBufferSlow("asdf")); - splited.Append(CreateBufferSlow("asdf")); - splited.Append(CreateBufferSlow("asdf")); - splited.Append(CreateBufferSlow("asdf")); - splited.Append(CreateBufferSlow("asdf")); - splited.Skip(32); - ASSERT_EQ(0, splited.ByteSize()); +TEST(NoncontiguousBuffer, Skip) +{ + NoncontiguousBuffer splited; + splited.Append(CreateBufferSlow("asdf")); + splited.Append(CreateBufferSlow("asdf")); + splited.Append(CreateBufferSlow("asdf")); + splited.Append(CreateBufferSlow("asdf")); + splited.Append(CreateBufferSlow("asdf")); + splited.Append(CreateBufferSlow("asdf")); + splited.Append(CreateBufferSlow("asdf")); + splited.Append(CreateBufferSlow("asdf")); + splited.Skip(32); + ASSERT_EQ(0, splited.ByteSize()); } -TEST(NoncontiguousBuffer, Skip2) { - NoncontiguousBuffer buffer; - EXPECT_TRUE(buffer.Empty()); - buffer.Skip(0); // Don't crash. - EXPECT_TRUE(buffer.Empty()); +TEST(NoncontiguousBuffer, Skip2) +{ + NoncontiguousBuffer buffer; + EXPECT_TRUE(buffer.Empty()); + buffer.Skip(0);// Don't crash. + EXPECT_TRUE(buffer.Empty()); } -TEST(NoncontiguousBuffer, FlattenSlow) { - NoncontiguousBuffer nb; - nb.Append(MakeNativeBuffer("asd4234")); - nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342")); - ASSERT_EQ("asd4234aXs", FlattenSlow(nb, 10)); +TEST(NoncontiguousBuffer, FlattenSlow) +{ + NoncontiguousBuffer nb; + nb.Append(MakeNativeBuffer("asd4234")); + nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342")); + ASSERT_EQ("asd4234aXs", FlattenSlow(nb, 10)); } -TEST(NoncontiguousBuffer, FlattenToSlow) { - struct C { - std::uint64_t ll; - int i; - bool f; - }; - NoncontiguousBuffer nb; - nb.Append(MakeNativeBuffer(Slice("\x12\x34\x56\x78\x9a\xbc\xde\xf0", 8))); - nb.Append(MakeNativeBuffer(Slice("\x12\x34\x56\x78", 4))); - nb.Append(MakeNativeBuffer(Slice("\x1", 1))); - nb.Append(MakeNativeBuffer(Slice("\x00\x00\x00", 3))); // Padding - C c; - FlattenToSlow(nb, &c, sizeof(C)); - ASSERT_EQ(0xf0debc9a78563412, c.ll); - ASSERT_EQ(0x78563412, c.i); - ASSERT_EQ(true, c.f); +TEST(NoncontiguousBuffer, FlattenToSlow) +{ + struct C { + std::uint64_t ll; + int i; + bool f; + }; + + NoncontiguousBuffer nb; + nb.Append(MakeNativeBuffer(Slice("\x12\x34\x56\x78\x9a\xbc\xde\xf0", 8))); + nb.Append(MakeNativeBuffer(Slice("\x12\x34\x56\x78", 4))); + nb.Append(MakeNativeBuffer(Slice("\x1", 1))); + nb.Append(MakeNativeBuffer(Slice("\x00\x00\x00", 3)));// Padding + C c; + FlattenToSlow(nb, &c, sizeof(C)); + ASSERT_EQ(0xf0debc9a78563412, c.ll); + ASSERT_EQ(0x78563412, c.i); + ASSERT_EQ(true, c.f); } -TEST(NoncontiguousBuffer, FlattenSlowUntil) { - NoncontiguousBuffer nb; - nb.Append(MakeNativeBuffer("asd4234")); - nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342")); - ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "aX")); - ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4")); - ASSERT_EQ("asd4234aXsdfsadfasdf2342", FlattenSlowUntil(nb, "2342")); - ASSERT_EQ("asd42", FlattenSlowUntil(nb, "z", 5)); - ASSERT_EQ("asd42", FlattenSlowUntil(nb, "3", 5)); - ASSERT_EQ("asd42", FlattenSlowUntil(nb, "2", 5)); - ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4", 5)); +TEST(NoncontiguousBuffer, FlattenSlowUntil) +{ + NoncontiguousBuffer nb; + nb.Append(MakeNativeBuffer("asd4234")); + nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342")); + ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "aX")); + ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4")); + ASSERT_EQ("asd4234aXsdfsadfasdf2342", FlattenSlowUntil(nb, "2342")); + ASSERT_EQ("asd42", FlattenSlowUntil(nb, "z", 5)); + ASSERT_EQ("asd42", FlattenSlowUntil(nb, "3", 5)); + ASSERT_EQ("asd42", FlattenSlowUntil(nb, "2", 5)); + ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4", 5)); } -TEST(NoncontiguousBuffer, FlattenSlowUntil2) { - auto nb = CreateBufferSlow( - "HTTP/1.1 200 OK\r\nRpc-SeqNo: 14563016719\r\nRpc-Error-Code: " - "0\r\nRpc-Error-Reason: The operation completed " - "successfully.\r\nContent-Type: " - "application/x-protobuf\r\nContent-Length: 0\r\n\r\nHTTP/1.1 200 " - "OK\r\nRpc-Seq"); - ASSERT_EQ("HTTP/1.1 200 OK\r\nRpc-SeqNo: 14563016719\r\nRpc-Error-Code: " - "0\r\nRpc-Error-Reason: The operation completed " - "successfully.\r\nContent-Type: " - "application/x-protobuf\r\nContent-Length: 0\r\n\r\n", - FlattenSlowUntil(nb, "\r\n\r\n")); +TEST(NoncontiguousBuffer, FlattenSlowUntil2) +{ + auto nb = CreateBufferSlow( + "HTTP/1.1 200 OK\r\nRpc-SeqNo: 14563016719\r\nRpc-Error-Code: " + "0\r\nRpc-Error-Reason: The operation completed " + "successfully.\r\nContent-Type: " + "application/x-protobuf\r\nContent-Length: 0\r\n\r\nHTTP/1.1 200 " + "OK\r\nRpc-Seq"); + ASSERT_EQ("HTTP/1.1 200 OK\r\nRpc-SeqNo: 14563016719\r\nRpc-Error-Code: " + "0\r\nRpc-Error-Reason: The operation completed " + "successfully.\r\nContent-Type: " + "application/x-protobuf\r\nContent-Length: 0\r\n\r\n", + FlattenSlowUntil(nb, "\r\n\r\n")); } -TEST(NoncontiguousBuffer, FlattenSlowUntil3) { - NoncontiguousBuffer nb; - nb.Append(MakeNativeBuffer("asd4234")); - nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342")); - ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "aX")); - ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4")); - ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "4aX")); +TEST(NoncontiguousBuffer, FlattenSlowUntil3) +{ + NoncontiguousBuffer nb; + nb.Append(MakeNativeBuffer("asd4234")); + nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342")); + ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "aX")); + ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4")); + ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "4aX")); } -TEST(NoncontiguousBuffer, FlattenSlowUntil4) { - NoncontiguousBuffer nb; - nb.Append(MakeNativeBuffer("AB")); - nb.Append(MakeNativeBuffer("CDEFGGGGHHHH")); - ASSERT_EQ("ABCDEFGGGG", FlattenSlowUntil(nb, "GGGG")); +TEST(NoncontiguousBuffer, FlattenSlowUntil4) +{ + NoncontiguousBuffer nb; + nb.Append(MakeNativeBuffer("AB")); + nb.Append(MakeNativeBuffer("CDEFGGGGHHHH")); + ASSERT_EQ("ABCDEFGGGG", FlattenSlowUntil(nb, "GGGG")); } -TEST(NoncontiguousBufferBuilder, Append) { - NoncontiguousBufferBuilder nbb; - nbb.Append(MakeForeignBuffer("")); - nbb.Append(MakeForeignBuffer("small")); - nbb.Append(MakeForeignBuffer(std::string(8192, 'a'))); - nbb.Append(CreateBufferSlow("")); - nbb.Append(CreateBufferSlow("small")); - nbb.Append(CreateBufferSlow(std::string(8192, 'a'))); - auto nb = nbb.DestructiveGet(); - EXPECT_EQ("small" + std::string(8192, 'a') + "small" + std::string(8192, 'a'), - FlattenSlow(nb)); +TEST(NoncontiguousBufferBuilder, Append) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append(MakeForeignBuffer("")); + nbb.Append(MakeForeignBuffer("small")); + nbb.Append(MakeForeignBuffer(std::string(8192, 'a'))); + nbb.Append(CreateBufferSlow("")); + nbb.Append(CreateBufferSlow("small")); + nbb.Append(CreateBufferSlow(std::string(8192, 'a'))); + auto nb = nbb.DestructiveGet(); + EXPECT_EQ("small" + std::string(8192, 'a') + "small" + std::string(8192, 'a'), FlattenSlow(nb)); } -TEST(NoncontiguousBufferBuilder, Reserve) { - auto temp_block = MakeNativeBufferBlock(); - auto max_bytes = temp_block->size(); - NoncontiguousBufferBuilder nbb; - auto ptr = nbb.data(); - auto ptr2 = nbb.Reserve(10); - ASSERT_EQ(ptr, ptr2); - ASSERT_EQ(ptr + 10, nbb.data()); - nbb.Append(std::string(max_bytes - 10 - 1, 'a')); - ptr = nbb.data(); - ptr2 = nbb.Reserve(1); // Last byte in the block. - ASSERT_EQ(ptr, ptr2); - ASSERT_EQ(max_bytes, nbb.SizeAvailable()); +TEST(NoncontiguousBufferBuilder, Reserve) +{ + auto temp_block = MakeNativeBufferBlock(); + auto max_bytes = temp_block->size(); + NoncontiguousBufferBuilder nbb; + auto ptr = nbb.data(); + auto ptr2 = nbb.Reserve(10); + ASSERT_EQ(ptr, ptr2); + ASSERT_EQ(ptr + 10, nbb.data()); + nbb.Append(std::string(max_bytes - 10 - 1, 'a')); + ptr = nbb.data(); + ptr2 = nbb.Reserve(1);// Last byte in the block. + ASSERT_EQ(ptr, ptr2); + ASSERT_EQ(max_bytes, nbb.SizeAvailable()); - nbb.Append(std::string(max_bytes - 1, 'a')); - ptr = nbb.data(); - ptr2 = nbb.Reserve(2); - ASSERT_NE(ptr, ptr2); - ASSERT_EQ(ptr2 + 2, nbb.data()); + nbb.Append(std::string(max_bytes - 1, 'a')); + ptr = nbb.data(); + ptr2 = nbb.Reserve(2); + ASSERT_NE(ptr, ptr2); + ASSERT_EQ(ptr2 + 2, nbb.data()); } -TEST(NoncontiguousBufferBuilder, DestructiveGet1) { - NoncontiguousBufferBuilder nbb; - nbb.Append("asdf1234", 6); - nbb.Append("1122", 4); - ASSERT_EQ("asdf12" - "1122", - FlattenSlow(nbb.DestructiveGet())); +TEST(NoncontiguousBufferBuilder, DestructiveGet1) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append("asdf1234", 6); + nbb.Append("1122", 4); + ASSERT_EQ("asdf12" + "1122", + FlattenSlow(nbb.DestructiveGet())); } -TEST(NoncontiguousBufferBuilder, DestructiveGet2) { - NoncontiguousBufferBuilder nbb; - nbb.Append("aabbccd"); - ASSERT_EQ("aabbccd", FlattenSlow(nbb.DestructiveGet())); +TEST(NoncontiguousBufferBuilder, DestructiveGet2) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append("aabbccd"); + ASSERT_EQ("aabbccd", FlattenSlow(nbb.DestructiveGet())); } -TEST(NoncontiguousBufferBuilder, DestructiveGet3) { - NoncontiguousBufferBuilder nbb; - nbb.Append(std::string(1000000, 'A')); - ASSERT_EQ(std::string(1000000, 'A'), FlattenSlow(nbb.DestructiveGet())); +TEST(NoncontiguousBufferBuilder, DestructiveGet3) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append(std::string(1000000, 'A')); + ASSERT_EQ(std::string(1000000, 'A'), FlattenSlow(nbb.DestructiveGet())); } -TEST(NoncontiguousBufferBuilder, DestructiveGet4) { - NoncontiguousBufferBuilder nbb; - nbb.Append('c'); - ASSERT_EQ("c", FlattenSlow(nbb.DestructiveGet())); +TEST(NoncontiguousBufferBuilder, DestructiveGet4) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append('c'); + ASSERT_EQ("c", FlattenSlow(nbb.DestructiveGet())); } -TEST(NoncontiguousBufferBuilder, DestructiveGet5) { - NoncontiguousBufferBuilder nbb; - nbb.Append(CreateBufferSlow("c")); - ASSERT_EQ("c", FlattenSlow(nbb.DestructiveGet())); +TEST(NoncontiguousBufferBuilder, DestructiveGet5) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append(CreateBufferSlow("c")); + ASSERT_EQ("c", FlattenSlow(nbb.DestructiveGet())); } -TEST(NoncontiguousBufferBuilder, DestructiveGet6) { - NoncontiguousBufferBuilder nbb; - nbb.Append(Slice("11"), Slice("2"), std::string("3"), std::string("45"), - Slice("6")); - nbb.Append("1122", 4); - ASSERT_EQ("11234561122", FlattenSlow(nbb.DestructiveGet())); +TEST(NoncontiguousBufferBuilder, DestructiveGet6) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append(Slice("11"), Slice("2"), std::string("3"), std::string("45"), Slice("6")); + nbb.Append("1122", 4); + ASSERT_EQ("11234561122", FlattenSlow(nbb.DestructiveGet())); } -TEST(MakeReferencingBuffer, Simple) { - NoncontiguousBufferBuilder nbb; - nbb.Append(MakeReferencingBuffer("abcdefg", 7)); - EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); +TEST(MakeReferencingBuffer, Simple) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append(MakeReferencingBuffer("abcdefg", 7)); + EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); } -TEST(MakeReferencingBuffer, WithCallbackSmallBufferOptimized) { - int x = 0; +TEST(MakeReferencingBuffer, WithCallbackSmallBufferOptimized) +{ + int x = 0; - NoncontiguousBufferBuilder nbb; - nbb.Append("aaa", 3); - // Small buffers are copied by `Append` and freed immediately. - nbb.Append(MakeReferencingBuffer("abcdefg", 7, [&] { ++x; })); - // Therefore the callback should have fired on return of `Append`. - EXPECT_EQ(1, x); - auto buffer = nbb.DestructiveGet(); - EXPECT_EQ("aaaabcdefg", FlattenSlow(buffer)); -} - -TEST(MakeReferencingBuffer, WithCallback) { - static const std::string kBuffer(12345, 'a'); - int x = 0; - - { NoncontiguousBufferBuilder nbb; nbb.Append("aaa", 3); - nbb.Append(MakeReferencingBuffer(kBuffer.data(), 1024, [&] { ++x; })); - EXPECT_EQ(0, x); + // Small buffers are copied by `Append` and freed immediately. + nbb.Append(MakeReferencingBuffer("abcdefg", 7, [&] { ++x; })); + // Therefore the callback should have fired on return of `Append`. + EXPECT_EQ(1, x); auto buffer = nbb.DestructiveGet(); - EXPECT_EQ(0, x); - EXPECT_EQ("aaa" + kBuffer.substr(0, 1024), FlattenSlow(buffer)); - } - EXPECT_EQ(1, x); + EXPECT_EQ("aaaabcdefg", FlattenSlow(buffer)); } -TEST(MakeForeignBuffer, String) { - NoncontiguousBufferBuilder nbb; - nbb.Append(MakeForeignBuffer(std::string("abcdefg"))); - EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); +TEST(MakeReferencingBuffer, WithCallback) +{ + static const std::string kBuffer(12345, 'a'); + int x = 0; + + { + NoncontiguousBufferBuilder nbb; + nbb.Append("aaa", 3); + nbb.Append(MakeReferencingBuffer(kBuffer.data(), 1024, [&] { ++x; })); + EXPECT_EQ(0, x); + auto buffer = nbb.DestructiveGet(); + EXPECT_EQ(0, x); + EXPECT_EQ("aaa" + kBuffer.substr(0, 1024), FlattenSlow(buffer)); + } + EXPECT_EQ(1, x); } -TEST(MakeForeignBuffer, VectorOfChar) { - std::vector data{'a', 'b', 'c', 'd', 'e', 'f', 'g'}; - NoncontiguousBufferBuilder nbb; - nbb.Append(MakeForeignBuffer(std::move(data))); - EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); +TEST(MakeForeignBuffer, String) +{ + NoncontiguousBufferBuilder nbb; + nbb.Append(MakeForeignBuffer(std::string("abcdefg"))); + EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); +} + +TEST(MakeForeignBuffer, VectorOfChar) +{ + std::vector data{'a', 'b', 'c', 'd', 'e', 'f', 'g'}; + NoncontiguousBufferBuilder nbb; + nbb.Append(MakeForeignBuffer(std::move(data))); + EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); } // TEST(MakeForeignBuffer, VectorOfBytes) { @@ -299,13 +327,14 @@ TEST(MakeForeignBuffer, VectorOfChar) { // EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); // } -TEST(MakeForeignBuffer, VectorOfUInt8) { - std::vector data; - data.resize(7); - memcpy(data.data(), "abcdefg", 7); - NoncontiguousBufferBuilder nbb; - nbb.Append(MakeForeignBuffer(std::move(data))); - EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); +TEST(MakeForeignBuffer, VectorOfUInt8) +{ + std::vector data; + data.resize(7); + memcpy(data.data(), "abcdefg", 7); + NoncontiguousBufferBuilder nbb; + nbb.Append(MakeForeignBuffer(std::move(data))); + EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet())); } -} // namespace tile +}// namespace tile diff --git a/tile/base/byte_order.h b/tile/base/byte_order.h index 7ac6fae..2fa16f1 100644 --- a/tile/base/byte_order.h +++ b/tile/base/byte_order.h @@ -41,86 +41,116 @@ namespace tile { -inline uint16_t ByteSwap16(uint16_t val) { return __builtin_bswap16(val); } -inline uint32_t ByteSwap32(uint32_t val) { return __builtin_bswap32(val); } -inline uint64_t ByteSwap64(uint64_t val) { return __builtin_bswap64(val); } +inline uint16_t +ByteSwap16(uint16_t val) +{ + return __builtin_bswap16(val); +} -inline bool IsHostLittleEndian() { +inline uint32_t +ByteSwap32(uint32_t val) +{ + return __builtin_bswap32(val); +} + +inline uint64_t +ByteSwap64(uint64_t val) +{ + return __builtin_bswap64(val); +} + +inline bool +IsHostLittleEndian() +{ #if TILE_LITTLE_ENDIAN == TILE_BYTE_ORDER - return true; + return true; #else - return false; + return false; #endif } -inline bool IsHostBigEndian() { +inline bool +IsHostBigEndian() +{ #if TILE_BIG_ENDIAN == TILE_BYTE_ORDER - return true; + return true; #else - return false; + return false; #endif } -inline uint16_t HostToNetwork16(uint16_t val_in_host) { +inline uint16_t +HostToNetwork16(uint16_t val_in_host) +{ #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - return val_in_host; + return val_in_host; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - return ByteSwap16(val_in_host); + return ByteSwap16(val_in_host); #else #error "Unsupported byte order" #endif } -inline uint32_t HostToNetwork32(uint32_t val_in_host) { +inline uint32_t +HostToNetwork32(uint32_t val_in_host) +{ #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - return val_in_host; + return val_in_host; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - return ByteSwap32(val_in_host); + return ByteSwap32(val_in_host); #else #error "Unsupported byte order" #endif } -inline uint64_t HostToNetwork64(uint64_t val_in_host) { +inline uint64_t +HostToNetwork64(uint64_t val_in_host) +{ #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - return val_in_host; + return val_in_host; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - return ByteSwap64(val_in_host); + return ByteSwap64(val_in_host); #else #error "Unsupported byte order" #endif } -inline uint16_t NetworkToHost16(uint16_t val_in_network) { +inline uint16_t +NetworkToHost16(uint16_t val_in_network) +{ #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - return val_in_network; + return val_in_network; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - return ByteSwap16(val_in_network); + return ByteSwap16(val_in_network); #else #error "Unsupported byte order" #endif } -inline uint32_t NetworkToHost32(uint32_t val_in_network) { +inline uint32_t +NetworkToHost32(uint32_t val_in_network) +{ #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - return val_in_network; + return val_in_network; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - return ByteSwap32(val_in_network); + return ByteSwap32(val_in_network); #else #error "Unsupported byte order" #endif } -inline uint64_t NetworkToHost64(uint64_t val_in_network) { +inline uint64_t +NetworkToHost64(uint64_t val_in_network) +{ #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - return val_in_network; + return val_in_network; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - return ByteSwap64(val_in_network); + return ByteSwap64(val_in_network); #else #error "Unsupported byte order" #endif } -} // namespace tile +}// namespace tile -#endif // TILE_BASE_BYTE_ORDER_H +#endif// TILE_BASE_BYTE_ORDER_H diff --git a/tile/base/byte_order_test.cc b/tile/base/byte_order_test.cc index 8bb17bd..65f285b 100644 --- a/tile/base/byte_order_test.cc +++ b/tile/base/byte_order_test.cc @@ -8,109 +8,123 @@ namespace tile { static union EndianHelper { - uint16_t v16; - uint32_t v32; - uint32_t v64; - uint8_t bytes[8]; -} endian_helper = {.bytes = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}}; + uint16_t v16; + uint32_t v32; + uint32_t v64; + uint8_t bytes[8]; +} endian_helper = { + .bytes = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07} +}; -TEST(ByteOrder, ByteSwap16) { - const uint16_t val = 0x1234; - const uint16_t expected = 0x3412; - ASSERT_EQ(expected, ByteSwap16(val)); -} -TEST(ByteOrder, ByteSwap32) { - const uint32_t val = 0x12345678; - const uint32_t expected = 0x78563412; - ASSERT_EQ(expected, ByteSwap32(val)); -} -TEST(ByteOrder, ByteSwap64) { - const uint64_t val = 0x1234567890abcdef; - const uint64_t expected = 0xefcdab9078563412; - ASSERT_EQ(expected, ByteSwap64(val)); +TEST(ByteOrder, ByteSwap16) +{ + const uint16_t val = 0x1234; + const uint16_t expected = 0x3412; + ASSERT_EQ(expected, ByteSwap16(val)); } -TEST(ByteOrder, IsHostByteOrder) { - ASSERT_NE(IsHostBigEndian(), IsHostLittleEndian()); +TEST(ByteOrder, ByteSwap32) +{ + const uint32_t val = 0x12345678; + const uint32_t expected = 0x78563412; + ASSERT_EQ(expected, ByteSwap32(val)); +} + +TEST(ByteOrder, ByteSwap64) +{ + const uint64_t val = 0x1234567890abcdef; + const uint64_t expected = 0xefcdab9078563412; + ASSERT_EQ(expected, ByteSwap64(val)); +} + +TEST(ByteOrder, IsHostByteOrder) +{ + ASSERT_NE(IsHostBigEndian(), IsHostLittleEndian()); #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - ASSERT_TRUE(IsHostBigEndian()); - ASSERT_FALSE(IsHostLittleEndian()); + ASSERT_TRUE(IsHostBigEndian()); + ASSERT_FALSE(IsHostLittleEndian()); #else - ASSERT_TRUE(IsHostLittleEndian()); - ASSERT_FALSE(IsHostBigEndian()); + ASSERT_TRUE(IsHostLittleEndian()); + ASSERT_FALSE(IsHostBigEndian()); #endif } -TEST(ByteOrder, HostToNetwork16) { - const uint16_t val = 0x1234; +TEST(ByteOrder, HostToNetwork16) +{ + const uint16_t val = 0x1234; #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - const uint16_t expected = val; + const uint16_t expected = val; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - const uint16_t expected = 0x3412; + const uint16_t expected = 0x3412; #else #error "Unsupported byte order" #endif - ASSERT_EQ(expected, HostToNetwork16(val)); + ASSERT_EQ(expected, HostToNetwork16(val)); } -TEST(ByteOrder, HostToNetwork32) { - const uint32_t val = 0x12345678; +TEST(ByteOrder, HostToNetwork32) +{ + const uint32_t val = 0x12345678; #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - const uint32_t expected = val; + const uint32_t expected = val; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - const uint32_t expected = 0x78563412; + const uint32_t expected = 0x78563412; #else #error "Unsupported byte order" #endif - ASSERT_EQ(expected, HostToNetwork32(val)); + ASSERT_EQ(expected, HostToNetwork32(val)); } -TEST(ByteOrder, HostToNetwork64) { - const uint64_t val = 0x1234567890abcdef; +TEST(ByteOrder, HostToNetwork64) +{ + const uint64_t val = 0x1234567890abcdef; #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - const uint64_t expected = val; + const uint64_t expected = val; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - const uint64_t expected = 0xefcdab9078563412; + const uint64_t expected = 0xefcdab9078563412; #else #error "Unsupported byte order" #endif - ASSERT_EQ(expected, HostToNetwork64(val)); + ASSERT_EQ(expected, HostToNetwork64(val)); } -TEST(ByteOrder, NetworkToHost16) { - const uint16_t val = 0x1234; +TEST(ByteOrder, NetworkToHost16) +{ + const uint16_t val = 0x1234; #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - const uint16_t expected = val; + const uint16_t expected = val; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - const uint16_t expected = 0x3412; + const uint16_t expected = 0x3412; #else #error "Unsupported byte order" #endif - ASSERT_EQ(expected, NetworkToHost16(val)); + ASSERT_EQ(expected, NetworkToHost16(val)); } -TEST(ByteOrder, NetworkToHost32) { - const uint32_t val = 0x12345678; +TEST(ByteOrder, NetworkToHost32) +{ + const uint32_t val = 0x12345678; #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - const uint32_t expected = val; + const uint32_t expected = val; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - const uint32_t expected = 0x78563412; + const uint32_t expected = 0x78563412; #else #error "Unsupported byte order" #endif - ASSERT_EQ(expected, NetworkToHost32(val)); + ASSERT_EQ(expected, NetworkToHost32(val)); } -TEST(ByteOrder, NetworkToHost64) { - const uint64_t val = 0x1234567890abcdef; +TEST(ByteOrder, NetworkToHost64) +{ + const uint64_t val = 0x1234567890abcdef; #if TILE_BYTE_ORDER == TILE_BIG_ENDIAN - const uint64_t expected = val; + const uint64_t expected = val; #elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN - const uint64_t expected = 0xefcdab9078563412; + const uint64_t expected = 0xefcdab9078563412; #else #error "Unsupported byte order" #endif - ASSERT_EQ(expected, NetworkToHost64(val)); + ASSERT_EQ(expected, NetworkToHost64(val)); } -} // namespace tile +}// namespace tile diff --git a/tile/base/casting.h b/tile/base/casting.h index a5ee6e1..7b1dadc 100644 --- a/tile/base/casting.h +++ b/tile/base/casting.h @@ -12,178 +12,200 @@ namespace tile { namespace detail { // Has classof -template struct HasClassofImpl { - template < - typename TT, typename TBase, - typename = enable_if_t())), bool>::value>> - static std::true_type test(int); - template static std::false_type test(...); +template +struct HasClassofImpl { + template())), bool>::value>> + static std::true_type test(int); + template + static std::false_type test(...); - static constexpr bool value = decltype(test(0))::value; + static constexpr bool value = decltype(test(0))::value; }; -} // namespace detail +}// namespace detail -template struct CastingTraits { - template - static auto RuntimeTypeCheck(const Base &val) - -> enable_if_t::value, bool> { - return T::classof(val); - } +template +struct CastingTraits { + template + static auto RuntimeTypeCheck(const Base &val) -> enable_if_t::value, bool> + { + return T::classof(val); + } - template - static auto RuntimeTypeCheck(const Base &val) - -> enable_if_t::value, bool> { - return dynamic_cast(&val) != nullptr; - } + template + static auto RuntimeTypeCheck(const Base &val) -> enable_if_t::value, bool> + { + return dynamic_cast(&val) != nullptr; + } }; class Castable { - class Dummy {}; + class Dummy {}; public: - friend void SetRuntimeType(Castable *ptr, int type, Dummy = {}) { - ptr->type_ = type; - } + friend void SetRuntimeType(Castable *ptr, int type, Dummy = {}) { ptr->type_ = type; } - friend int GetRuntimeType(const Castable &val, Dummy = {}) { - return val.type_; - } + friend int GetRuntimeType(const Castable &val, Dummy = {}) { return val.type_; } protected: - template friend struct CastingTraits; - ~Castable() = default; + template + friend struct CastingTraits; + ~Castable() = default; - template void SetRuntimeTypeTo() { - SetRuntimeType(this, GetRuntimeTypeId()); - } + template + void SetRuntimeTypeTo() + { + SetRuntimeType(this, GetRuntimeTypeId()); + } - template int GetRuntimeType() const { - return GetRuntimeTypeId(); - } + template + int GetRuntimeType() const + { + return GetRuntimeTypeId(); + } - template static int GetRuntimeTypeId() { - static const int value = internal::IndexAlloc::For()->Next(); - return value; - } + template + static int GetRuntimeTypeId() + { + static const int value = internal::IndexAlloc::For()->Next(); + return value; + } private: - std::int_fast32_t type_ = GetRuntimeTypeId(); + std::int_fast32_t type_ = GetRuntimeTypeId(); }; // ExactMatchCastable class ExactMatchCastable : public Castable { protected: - ~ExactMatchCastable() = default; + ~ExactMatchCastable() = default; }; -template -struct CastingTraits< - T, enable_if_t::value>> { - static bool RuntimeTypeCheck(const ExactMatchCastable &object) { - return GetRuntimeType(object) == Castable::GetRuntimeTypeId(); - } +template +struct CastingTraits::value>> { + static bool RuntimeTypeCheck(const ExactMatchCastable &object) + { + return GetRuntimeType(object) == Castable::GetRuntimeTypeId(); + } }; namespace casting { namespace detail { -template ::value && - !std::is_same::value>> -inline bool RuntimeTypeCheck(const Base &val) { - return CastingTraits::RuntimeTypeCheck(val); +template::value && !std::is_same::value>> +inline bool +RuntimeTypeCheck(const Base &val) +{ + return CastingTraits::RuntimeTypeCheck(val); } -template inline bool RuntimeTypeCheck(const T &val) { - return true; +template +inline bool +RuntimeTypeCheck(const T &val) +{ + return true; } -template -using casted_type_t = - internal::conditional_t::value, const T *, T *>; +template +using casted_type_t = internal::conditional_t::value, const T *, T *>; -template -auto ReallyCastable(Base *ptr) - -> enable_if_t::value, bool> { - return dynamic_cast(ptr) != nullptr; -} -template -auto ReallyCastable(Base *ptr) - -> enable_if_t::value, bool> { - return typeid(T) == typeid(*ptr); +template +auto +ReallyCastable(Base *ptr) -> enable_if_t::value, bool> +{ + return dynamic_cast(ptr) != nullptr; } -template void InvalidCast(Base *ptr) { - if (ReallyCastable(ptr)) { - TILE_LOG_FATAL( - "Casting to type [{}] failed. However, the C++ runtime reports that " - "you're indeed casting to the (right) runtime type of the object. This " - "can happen when either: 1) you haven't initialize object's runtime " - "type correctly (e.g. via `SetRuntimeTypeTo` if you're inheriting from " - "`ExactMatchCast`), or 2) the implementation of your `classof` is " - "incorrect.", - GetTypeName()); - } else { - TILE_LOG_FATAL( - "Invalid cast: Runtime type [{}] expected, got [{}]. If you believe " - "this is an error, check if your `classof` is implemented correctly", - GetTypeName(), GetTypeName(*ptr)); - } - TILE_UNREACHABLE(""); +template +auto +ReallyCastable(Base *ptr) -> enable_if_t::value, bool> +{ + return typeid(T) == typeid(*ptr); } -} // namespace detail -} // namespace casting - -template ::value>> -inline bool isa(const Base &val) { - return casting::detail::RuntimeTypeCheck(val); +template +void +InvalidCast(Base *ptr) +{ + if (ReallyCastable(ptr)) { + TILE_LOG_FATAL("Casting to type [{}] failed. However, the C++ runtime reports that " + "you're indeed casting to the (right) runtime type of the object. This " + "can happen when either: 1) you haven't initialize object's runtime " + "type correctly (e.g. via `SetRuntimeTypeTo` if you're inheriting from " + "`ExactMatchCast`), or 2) the implementation of your `classof` is " + "incorrect.", + GetTypeName()); + } else { + TILE_LOG_FATAL("Invalid cast: Runtime type [{}] expected, got [{}]. If you believe " + "this is an error, check if your `classof` is implemented correctly", + GetTypeName(), GetTypeName(*ptr)); + } + TILE_UNREACHABLE(""); } -template inline bool isa(const Base *val) { - return isa(*val); +}// namespace detail +}// namespace casting + +template::value>> +inline bool +isa(const Base &val) +{ + return casting::detail::RuntimeTypeCheck(val); } -template > -R dyn_cast(Base *ptr) { - return isa(ptr) ? static_cast(ptr) : nullptr; +template +inline bool +isa(const Base *val) +{ + return isa(*val); } -template ::value>> +template> +R +dyn_cast(Base *ptr) +{ + return isa(ptr) ? static_cast(ptr) : nullptr; +} + +template::value>> inline auto -dyn_cast(Base &val) -> decltype(dyn_cast(std::declval())) { - return dyn_cast(&val); +dyn_cast(Base &val) -> decltype(dyn_cast(std::declval())) +{ + return dyn_cast(&val); } -template -inline auto dyn_cast_or_null(Base *ptr) -> decltype(dyn_cast(ptr)) { - return ptr ? dyn_cast(ptr) : nullptr; +template +inline auto +dyn_cast_or_null(Base *ptr) -> decltype(dyn_cast(ptr)) +{ + return ptr ? dyn_cast(ptr) : nullptr; } -template > -inline R cast(Base *ptr) { - if (TILE_LIKELY(isa(ptr))) { - return static_cast(ptr); - } - casting::detail::InvalidCast(ptr); - return nullptr; +template> +inline R +cast(Base *ptr) +{ + if (TILE_LIKELY(isa(ptr))) { return static_cast(ptr); } + casting::detail::InvalidCast(ptr); + return nullptr; } -template ::value>> -inline auto cast(Base &val) -> decltype(cast(std::declval())) { - return cast(&val); +template::value>> +inline auto +cast(Base &val) -> decltype(cast(std::declval())) +{ + return cast(&val); } -template -inline auto cast_or_null(Base *ptr) -> decltype(cast(ptr)) { - return ptr ? cast(ptr) : nullptr; +template +inline auto +cast_or_null(Base *ptr) -> decltype(cast(ptr)) +{ + return ptr ? cast(ptr) : nullptr; } -} // namespace tile +}// namespace tile -#endif // TILE_BASE_CASTING_H +#endif// TILE_BASE_CASTING_H diff --git a/tile/base/casting_benchmark.cc b/tile/base/casting_benchmark.cc index 9b08b07..830e7f3 100644 --- a/tile/base/casting_benchmark.cc +++ b/tile/base/casting_benchmark.cc @@ -7,64 +7,63 @@ namespace tile { struct Base { - virtual ~Base() = default; - enum { kA, kB, kC [[maybe_unused]] } type; + virtual ~Base() = default; + + enum { kA, kB, kC [[maybe_unused]] } type; }; struct A : Base { - A() { type = kA; } + A() { type = kA; } - static bool classof(const Base &val) { - return val.type == kA || val.type == kB; - } + static bool classof(const Base &val) { return val.type == kA || val.type == kB; } }; struct B : A { - B() { type = kB; } + B() { type = kB; } - static bool classof(const Base &val) { return val.type == kB; } + static bool classof(const Base &val) { return val.type == kB; } }; -auto pb = make_unique(); +auto pb = make_unique(); Base *ptr = pb.get(); volatile A *converted_ptr; struct C1 : ExactMatchCastable {}; struct C2 : C1 { - C2() { SetRuntimeType(this, GetRuntimeTypeId()); } + C2() { SetRuntimeType(this, GetRuntimeTypeId()); } }; struct C3 : C1 { - C3() { SetRuntimeType(this, GetRuntimeTypeId()); } + C3() { SetRuntimeType(this, GetRuntimeTypeId()); } }; auto pc2 = make_unique(); -C1 *pc1 = pc2.get(); +C1 *pc1 = pc2.get(); volatile C3 *pc3; -void Benchmark_BuiltinDynamicCast(benchmark::State &state) { - while (state.KeepRunning()) { - converted_ptr = dynamic_cast(ptr); - } +void +Benchmark_BuiltinDynamicCast(benchmark::State &state) +{ + while (state.KeepRunning()) { converted_ptr = dynamic_cast(ptr); } } BENCHMARK(Benchmark_BuiltinDynamicCast); -void Benchmark_DynCast(benchmark::State &state) { - while (state.KeepRunning()) { - converted_ptr = dyn_cast(ptr); - } +void +Benchmark_DynCast(benchmark::State &state) +{ + while (state.KeepRunning()) { converted_ptr = dyn_cast(ptr); } } BENCHMARK(Benchmark_DynCast); -void Benchmark_ExactMatchCastableDynCast(benchmark::State &state) { - while (state.KeepRunning()) { - pc3 = dyn_cast(pc1); - } +void +Benchmark_ExactMatchCastableDynCast(benchmark::State &state) +{ + while (state.KeepRunning()) { pc3 = dyn_cast(pc1); } } BENCHMARK(Benchmark_ExactMatchCastableDynCast); -} // namespace tile +}// namespace tile diff --git a/tile/base/casting_test.cc b/tile/base/casting_test.cc index 1d9985e..9e2ce47 100644 --- a/tile/base/casting_test.cc +++ b/tile/base/casting_test.cc @@ -9,95 +9,99 @@ namespace tile { struct Base { - enum { kA, kB, kC } type; + enum { kA, kB, kC } type; }; struct A : Base { - A() { type = kA; } + A() { type = kA; } - static bool classof(const Base &val) { - return val.type == kA || val.type == kB; - } + static bool classof(const Base &val) { return val.type == kA || val.type == kB; } }; struct B : A { - B() { type = kB; } + B() { type = kB; } - static bool classof(const Base &val) { return val.type == kB; } + static bool classof(const Base &val) { return val.type == kB; } }; struct C : Base { - C() { type = kC; } + C() { type = kC; } - static bool classof(const Base &val) { return val.type == kC; } + static bool classof(const Base &val) { return val.type == kC; } }; struct C1 : ExactMatchCastable {}; struct C2 : C1 { - C2() { SetRuntimeType(this, GetRuntimeTypeId()); } + C2() { SetRuntimeType(this, GetRuntimeTypeId()); } }; struct C3 : C1 { - C3() { SetRuntimeType(this, GetRuntimeTypeId()); } + C3() { SetRuntimeType(this, GetRuntimeTypeId()); } }; -TEST(CastingDeathTest, InvalidCast) { - auto pa = make_unique(); - ASSERT_DEATH(cast(pa.get()), "Invalid cast"); +TEST(CastingDeathTest, InvalidCast) +{ + auto pa = make_unique(); + ASSERT_DEATH(cast(pa.get()), "Invalid cast"); } -TEST(Casting, Nullptr) { - B *pb = nullptr; - ASSERT_EQ(nullptr, dyn_cast_or_null(pb)); - ASSERT_EQ(nullptr, cast_or_null(pb)); +TEST(Casting, Nullptr) +{ + B *pb = nullptr; + ASSERT_EQ(nullptr, dyn_cast_or_null(pb)); + ASSERT_EQ(nullptr, cast_or_null(pb)); } -TEST(Casting, DownCastFailure) { - auto pa = make_unique(); - ASSERT_EQ(nullptr, dyn_cast(pa.get())); +TEST(Casting, DownCastFailure) +{ + auto pa = make_unique(); + ASSERT_EQ(nullptr, dyn_cast(pa.get())); } -TEST(Casting, Cast) { - auto pb = make_unique(); - Base *ptr = pb.get(); +TEST(Casting, Cast) +{ + auto pb = make_unique(); + Base *ptr = pb.get(); - ASSERT_NE(nullptr, dyn_cast(ptr)); - ASSERT_NE(nullptr, dyn_cast(ptr)); - ASSERT_NE(nullptr, dyn_cast(ptr)); + ASSERT_NE(nullptr, dyn_cast(ptr)); + ASSERT_NE(nullptr, dyn_cast(ptr)); + ASSERT_NE(nullptr, dyn_cast(ptr)); - ASSERT_NE(nullptr, cast(ptr)); // Casting pointer. - ASSERT_NE(nullptr, cast(ptr)); // Casting pointer. - ASSERT_NE(nullptr, cast(*ptr)); // Casting pointer. - ASSERT_NE(nullptr, cast(*ptr)); // Casting pointer. + ASSERT_NE(nullptr, cast(ptr)); // Casting pointer. + ASSERT_NE(nullptr, cast(ptr)); // Casting pointer. + ASSERT_NE(nullptr, cast(*ptr));// Casting pointer. + ASSERT_NE(nullptr, cast(*ptr));// Casting pointer. - ASSERT_NE(nullptr, dyn_cast(pb.get())); // Cast to self. - ASSERT_EQ(nullptr, dyn_cast(ptr)); // Cast failure. + ASSERT_NE(nullptr, dyn_cast(pb.get()));// Cast to self. + ASSERT_EQ(nullptr, dyn_cast(ptr)); // Cast failure. } -TEST(Casting, CastWithConst) { - auto pb = make_unique(); - const Base *ptr = pb.get(); +TEST(Casting, CastWithConst) +{ + auto pb = make_unique(); + const Base *ptr = pb.get(); - ASSERT_NE(nullptr, dyn_cast(ptr)); - ASSERT_NE(nullptr, dyn_cast(ptr)); - ASSERT_NE(nullptr, dyn_cast(ptr)); + ASSERT_NE(nullptr, dyn_cast(ptr)); + ASSERT_NE(nullptr, dyn_cast(ptr)); + ASSERT_NE(nullptr, dyn_cast(ptr)); - ASSERT_NE(nullptr, cast(ptr)); // Casting pointer. - ASSERT_NE(nullptr, cast(ptr)); // Casting pointer. - ASSERT_NE(nullptr, cast(*ptr)); // Casting pointer. - ASSERT_NE(nullptr, cast(*ptr)); // Casting pointer. + ASSERT_NE(nullptr, cast(ptr)); // Casting pointer. + ASSERT_NE(nullptr, cast(ptr)); // Casting pointer. + ASSERT_NE(nullptr, cast(*ptr));// Casting pointer. + ASSERT_NE(nullptr, cast(*ptr));// Casting pointer. - ASSERT_NE(nullptr, dyn_cast(pb.get())); // Cast to self. - ASSERT_EQ(nullptr, dyn_cast(ptr)); // Cast failure. + ASSERT_NE(nullptr, dyn_cast(pb.get()));// Cast to self. + ASSERT_EQ(nullptr, dyn_cast(ptr)); // Cast failure. } -TEST(Casting, ExactMatchCastable) { - auto pc2 = make_unique(); - C1 *p = pc2.get(); - ASSERT_NE(nullptr, dyn_cast(p)); // Success. - ASSERT_NE(nullptr, dyn_cast(p)); // Success. - ASSERT_EQ(nullptr, dyn_cast(p)); // Failure. +TEST(Casting, ExactMatchCastable) +{ + auto pc2 = make_unique(); + C1 *p = pc2.get(); + ASSERT_NE(nullptr, dyn_cast(p));// Success. + ASSERT_NE(nullptr, dyn_cast(p));// Success. + ASSERT_EQ(nullptr, dyn_cast(p));// Failure. } -} // namespace tile +}// namespace tile diff --git a/tile/base/chrono.cc b/tile/base/chrono.cc index 1cba8f4..7e2c878 100644 --- a/tile/base/chrono.cc +++ b/tile/base/chrono.cc @@ -15,132 +15,150 @@ namespace tile { namespace { -template struct Epoch {}; -template <> struct Epoch { - static constexpr auto value = - std::chrono::duration_cast( - std::chrono::seconds(0)); +template +struct Epoch {}; + +template<> +struct Epoch { + static constexpr auto value = std::chrono::duration_cast(std::chrono::seconds(0)); }; -template <> struct Epoch { - static constexpr auto value = - std::chrono::duration_cast( - std::chrono::seconds(1716543273)); +template<> +struct Epoch { + static constexpr auto value = + std::chrono::duration_cast(std::chrono::seconds(1716543273)); }; -template -inline typename Clock::time_point ReadClock(clockid_t type) { - timespec ts; - clock_gettime(type, &ts); - const long long ns = ts.tv_sec * 1000LL * 1000LL * 1000LL + ts.tv_nsec; - auto duration = std::chrono::duration_cast( - std::chrono::nanoseconds(ns)); - return typename Clock::time_point(duration); +template +inline typename Clock::time_point +ReadClock(clockid_t type) +{ + timespec ts; + clock_gettime(type, &ts); + const long long ns = ts.tv_sec * 1000LL * 1000LL * 1000LL + ts.tv_nsec; + auto duration = std::chrono::duration_cast(std::chrono::nanoseconds(ns)); + return typename Clock::time_point(duration); } -void Sleep(long ns) { - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = (ns + 999) / 1000; +void +Sleep(long ns) +{ + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = (ns + 999) / 1000; - select(0, NULL, NULL, NULL, &timeout); + select(0, NULL, NULL, NULL, &timeout); } -} // namespace +}// namespace + namespace detail { namespace chrono { -struct alignas(hardware_destructive_interference_size) - AsynchronouslyUpdatedTimestamps { - std::atomic steady_clock_time_since_epoch; - std::atomic system_clock_time_since_epoch; +struct alignas(hardware_destructive_interference_size) AsynchronouslyUpdatedTimestamps { + std::atomic steady_clock_time_since_epoch; + std::atomic system_clock_time_since_epoch; }; + static AsynchronouslyUpdatedTimestamps async_updated_timestamps; -void UpdateCoarseTimestamps() { - async_updated_timestamps.steady_clock_time_since_epoch.store( - ReadSteadyClock().time_since_epoch(), - // std::chrono::steady_clock::now().time_since_epoch(), - std::memory_order_relaxed); - async_updated_timestamps.system_clock_time_since_epoch.store( - ReadSystemClock().time_since_epoch(), - // std::chrono::system_clock::now().time_since_epoch(), - std::memory_order_relaxed); +void +UpdateCoarseTimestamps() +{ + async_updated_timestamps.steady_clock_time_since_epoch.store( + ReadSteadyClock().time_since_epoch(), + // std::chrono::steady_clock::now().time_since_epoch(), + std::memory_order_relaxed); + async_updated_timestamps.system_clock_time_since_epoch.store( + ReadSystemClock().time_since_epoch(), + // std::chrono::system_clock::now().time_since_epoch(), + std::memory_order_relaxed); } + constexpr std::chrono::microseconds CoarseClockInitializer::kAccuracy; -CoarseClockInitializer *CoarseClockInitializer::Instance() { - static NeverDestroyedSingleton cci; - return cci.Get(); + +CoarseClockInitializer * +CoarseClockInitializer::Instance() +{ + static NeverDestroyedSingleton cci; + return cci.Get(); } -void CoarseClockInitializer::Start() { - if (!internal::TestAndSet(running_, false, true)) { - TILE_LOG_WARNING("CoarseClockInitializer is already running"); - return; - } - - UpdateCoarseTimestamps(); - - worker_ = make_unique([this] { - const auto accuracy_as_ns = - std::chrono::duration_cast(kAccuracy).count(); - TILE_CHECK_GE(accuracy_as_ns, 2000, - "accuracy is too small, MUST GE 2000ns, current is {}", - kAccuracy); - - while (running_.load(std::memory_order_relaxed)) { - // std::this_thread::sleep_for(std::chrono::nanoseconds(500)); - UpdateCoarseTimestamps(); - // Sleep(accuracy_as_ns / 2); - std::this_thread::sleep_for(kAccuracy / 2); +void +CoarseClockInitializer::Start() +{ + if (!internal::TestAndSet(running_, false, true)) { + TILE_LOG_WARNING("CoarseClockInitializer is already running"); + return; } - }); + + UpdateCoarseTimestamps(); + + worker_ = make_unique([this] { + const auto accuracy_as_ns = std::chrono::duration_cast(kAccuracy).count(); + TILE_CHECK_GE(accuracy_as_ns, 2000, "accuracy is too small, MUST GE 2000ns, current is {}", kAccuracy); + + while (running_.load(std::memory_order_relaxed)) { + // std::this_thread::sleep_for(std::chrono::nanoseconds(500)); + UpdateCoarseTimestamps(); + // Sleep(accuracy_as_ns / 2); + std::this_thread::sleep_for(kAccuracy / 2); + } + }); } -void CoarseClockInitializer::Stop() { - running_.store(false, std::memory_order_relaxed); +void +CoarseClockInitializer::Stop() +{ + running_.store(false, std::memory_order_relaxed); } -void CoarseClockInitializer::Join() { - if (worker_) { - worker_->join(); - worker_.reset(); - } +void +CoarseClockInitializer::Join() +{ + if (worker_) { + worker_->join(); + worker_.reset(); + } } CoarseClockInitializer::CoarseClockInitializer() {} CoarseClockInitializer::~CoarseClockInitializer() {} -} // namespace chrono -} // namespace detail +}// namespace chrono +}// namespace detail -std::chrono::steady_clock::time_point ReadSteadyClock() { - // return ReadClock(CLOCK_MONOTONIC); - return std::chrono::steady_clock::now(); -} -std::chrono::system_clock::time_point ReadSystemClock() { - // return ReadClock(CLOCK_REALTIME); - return std::chrono::system_clock::now(); +std::chrono::steady_clock::time_point +ReadSteadyClock() +{ + // return ReadClock(CLOCK_MONOTONIC); + return std::chrono::steady_clock::now(); } -std::chrono::steady_clock::time_point ReadCoarseSteadyClock() { - auto coarse_duration = - detail::chrono::async_updated_timestamps.steady_clock_time_since_epoch - .load(std::memory_order_relaxed); - auto target_duration = - std::chrono::duration_cast( - coarse_duration); - return std::chrono::steady_clock::time_point(target_duration); +std::chrono::system_clock::time_point +ReadSystemClock() +{ + // return ReadClock(CLOCK_REALTIME); + return std::chrono::system_clock::now(); } -std::chrono::system_clock::time_point ReadCoarseSystemClock() { - auto coarse_duration = - detail::chrono::async_updated_timestamps.system_clock_time_since_epoch - .load(std::memory_order_relaxed); - auto target_duration = - std::chrono::duration_cast( - coarse_duration); - - return std::chrono::system_clock::time_point(target_duration); +std::chrono::steady_clock::time_point +ReadCoarseSteadyClock() +{ + auto coarse_duration = + detail::chrono::async_updated_timestamps.steady_clock_time_since_epoch.load(std::memory_order_relaxed); + auto target_duration = std::chrono::duration_cast(coarse_duration); + return std::chrono::steady_clock::time_point(target_duration); } -} // namespace tile + +std::chrono::system_clock::time_point +ReadCoarseSystemClock() +{ + auto coarse_duration = + detail::chrono::async_updated_timestamps.system_clock_time_since_epoch.load(std::memory_order_relaxed); + + auto target_duration = std::chrono::duration_cast(coarse_duration); + + return std::chrono::system_clock::time_point(target_duration); +} +}// namespace tile diff --git a/tile/base/chrono.h b/tile/base/chrono.h index 7107782..415ff10 100644 --- a/tile/base/chrono.h +++ b/tile/base/chrono.h @@ -17,26 +17,26 @@ namespace chrono { class CoarseClockInitializer { public: - static constexpr auto kAccuracy = std::chrono::microseconds(500); - static CoarseClockInitializer *Instance(); + static constexpr auto kAccuracy = std::chrono::microseconds(500); + static CoarseClockInitializer *Instance(); - // for `tile::Start()` - void Start(); - void Stop(); - void Join(); + // for `tile::Start()` + void Start(); + void Stop(); + void Join(); private: - ~CoarseClockInitializer(); - CoarseClockInitializer(); - friend NeverDestroyedSingleton; + ~CoarseClockInitializer(); + CoarseClockInitializer(); + friend NeverDestroyedSingleton; private: - std::unique_ptr worker_; - std::atomic running_{false}; + std::unique_ptr worker_; + std::atomic running_{false}; }; -} // namespace chrono -} // namespace detail +}// namespace chrono +}// namespace detail std::chrono::steady_clock::time_point ReadSteadyClock(); std::chrono::system_clock::time_point ReadSystemClock(); @@ -45,10 +45,13 @@ std::chrono::system_clock::time_point ReadSystemClock(); std::chrono::steady_clock::time_point ReadCoarseSteadyClock(); // accuracy: 10us std::chrono::system_clock::time_point ReadCoarseSystemClock(); -inline std::int64_t ReadUnixTimestamp() { - return ReadCoarseSystemClock().time_since_epoch() / std::chrono::seconds(1); + +inline std::int64_t +ReadUnixTimestamp() +{ + return ReadCoarseSystemClock().time_since_epoch() / std::chrono::seconds(1); } -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_CHRONO_H +#endif// _TILE_BASE_CHRONO_H diff --git a/tile/base/chrono_benchmark.cc b/tile/base/chrono_benchmark.cc index 7e04423..9b0819e 100644 --- a/tile/base/chrono_benchmark.cc +++ b/tile/base/chrono_benchmark.cc @@ -8,63 +8,67 @@ namespace tile { -void Benchmark_GetTimeOfDay(benchmark::State &state) { - while (state.KeepRunning()) { - struct timeval tv; - gettimeofday(&tv, nullptr); - } +void +Benchmark_GetTimeOfDay(benchmark::State &state) +{ + while (state.KeepRunning()) { + struct timeval tv; + gettimeofday(&tv, nullptr); + } } BENCHMARK(Benchmark_GetTimeOfDay); -void Benchmark_StdSteadyClock(benchmark::State &state) { - while (state.KeepRunning()) { - (void)std::chrono::steady_clock::now(); - } +void +Benchmark_StdSteadyClock(benchmark::State &state) +{ + while (state.KeepRunning()) { (void) std::chrono::steady_clock::now(); } } BENCHMARK(Benchmark_StdSteadyClock); -void Benchmark_StdSystemClock(benchmark::State &state) { - while (state.KeepRunning()) { - (void)std::chrono::system_clock::now(); - } +void +Benchmark_StdSystemClock(benchmark::State &state) +{ + while (state.KeepRunning()) { (void) std::chrono::system_clock::now(); } } BENCHMARK(Benchmark_StdSystemClock); -void Benchmark_ReadSteadyClock(benchmark::State &state) { - while (state.KeepRunning()) { - ReadSteadyClock(); - } +void +Benchmark_ReadSteadyClock(benchmark::State &state) +{ + while (state.KeepRunning()) { ReadSteadyClock(); } } BENCHMARK(Benchmark_ReadSteadyClock); -void Benchmark_ReadSystemClock(benchmark::State &state) { - while (state.KeepRunning()) { - ReadSystemClock(); - } +void +Benchmark_ReadSystemClock(benchmark::State &state) +{ + while (state.KeepRunning()) { ReadSystemClock(); } } BENCHMARK(Benchmark_ReadSystemClock); -void Benchmark_ReadCoarseSteadyClock(benchmark::State &state) { - while (state.KeepRunning()) { - // ... <+23>: lea 0x137c5a(%rip),%rax # `system_clock_time_since_epoch` - // ... <+30>: mov (%rax),%rax - ReadCoarseSteadyClock(); - } +void +Benchmark_ReadCoarseSteadyClock(benchmark::State &state) +{ + while (state.KeepRunning()) { + // ... <+23>: lea 0x137c5a(%rip),%rax # `system_clock_time_since_epoch` + // ... <+30>: mov (%rax),%rax + ReadCoarseSteadyClock(); + } } BENCHMARK(Benchmark_ReadCoarseSteadyClock); -void Benchmark_ReadCoarseSystemClock(benchmark::State &state) { - while (state.KeepRunning()) { - ReadCoarseSystemClock(); - } +void +Benchmark_ReadCoarseSystemClock(benchmark::State &state) +{ + while (state.KeepRunning()) { ReadCoarseSystemClock(); } } BENCHMARK(Benchmark_ReadCoarseSystemClock); -} // namespace tile +}// namespace tile diff --git a/tile/base/chrono_test.cc b/tile/base/chrono_test.cc index 524fbce..6bee577 100644 --- a/tile/base/chrono_test.cc +++ b/tile/base/chrono_test.cc @@ -7,42 +7,38 @@ namespace tile { static constexpr auto one_ms = std::chrono::milliseconds(1); static constexpr auto kTestN = 1000; -long AvageTime(std::function f, std::size_t n = kTestN) { - long double total = 0; - for (std::size_t i = 0; i != n; ++i) { - total += 1.0f / n * f(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - return static_cast(total); +long +AvageTime(std::function f, std::size_t n = kTestN) +{ + long double total = 0; + for (std::size_t i = 0; i != n; ++i) { + total += 1.0f / n * f(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + return static_cast(total); } -TEST(SystemClock, Compare) { - auto diff = AvageTime([] { - return (ReadSystemClock() - std::chrono::system_clock::now()) / one_ms; - }); - ASSERT_NEAR(diff, 0, 5); +TEST(SystemClock, Compare) +{ + auto diff = AvageTime([] { return (ReadSystemClock() - std::chrono::system_clock::now()) / one_ms; }); + ASSERT_NEAR(diff, 0, 5); } -TEST(SteadyClock, Compare) { - auto diff = AvageTime([] { - return (ReadSteadyClock() - std::chrono::steady_clock::now()) / one_ms; - }); - ASSERT_NEAR(diff, 0, 5); +TEST(SteadyClock, Compare) +{ + auto diff = AvageTime([] { return (ReadSteadyClock() - std::chrono::steady_clock::now()) / one_ms; }); + ASSERT_NEAR(diff, 0, 5); } -TEST(CoarseSystemClock, Compare) { - auto diff = AvageTime([] { - return (ReadCoarseSystemClock() - std::chrono::system_clock::now()) / - one_ms; - }); - ASSERT_NEAR(diff, 0, kTestN); +TEST(CoarseSystemClock, Compare) +{ + auto diff = AvageTime([] { return (ReadCoarseSystemClock() - std::chrono::system_clock::now()) / one_ms; }); + ASSERT_NEAR(diff, 0, kTestN); } -TEST(CoarseSteadyClock, Compare) { - auto diff = AvageTime([] { - return (ReadCoarseSteadyClock() - std::chrono::steady_clock::now()) / - one_ms; - }); - ASSERT_NEAR(diff, 0, kTestN); +TEST(CoarseSteadyClock, Compare) +{ + auto diff = AvageTime([] { return (ReadCoarseSteadyClock() - std::chrono::steady_clock::now()) / one_ms; }); + ASSERT_NEAR(diff, 0, kTestN); } -} // namespace tile +}// namespace tile diff --git a/tile/base/compression.cc b/tile/base/compression.cc index da0b1f2..54977ef 100644 --- a/tile/base/compression.cc +++ b/tile/base/compression.cc @@ -4,89 +4,96 @@ namespace tile { -std::unique_ptr MakeDecompressor(Slice name) { - return decompressor_registry.TryNew(name); +std::unique_ptr +MakeDecompressor(Slice name) +{ + return decompressor_registry.TryNew(name); } -std::unique_ptr MakeCompressor(Slice name) { - return compressor_registry.TryNew(name); +std::unique_ptr +MakeCompressor(Slice name) +{ + return compressor_registry.TryNew(name); } -std::optional Compress(Compressor *compressor, - const NoncontiguousBuffer &body) { - NoncontiguousBufferBuilder builder; - if (!Compress(compressor, body, &builder)) { - return std::nullopt; - } - return builder.DestructiveGet(); -} -std::optional Compress(Compressor *compressor, - Slice body) { - NoncontiguousBufferBuilder builder; - if (!Compress(compressor, body, &builder)) { - return std::nullopt; - } - return builder.DestructiveGet(); +std::optional +Compress(Compressor *compressor, const NoncontiguousBuffer &body) +{ + NoncontiguousBufferBuilder builder; + if (!Compress(compressor, body, &builder)) { return std::nullopt; } + return builder.DestructiveGet(); } -bool Compress(Compressor *compressor, const NoncontiguousBuffer &nb, - NoncontiguousBufferBuilder *builder) { - if (!compressor) { - TILE_LOG_WARNING_EVERY_SECOND("Compressor nullptr"); - return false; - } - - NoncontiguousBufferCompressionOutputStream out(builder); - return compressor->Compress(nb, &out); +std::optional +Compress(Compressor *compressor, Slice body) +{ + NoncontiguousBufferBuilder builder; + if (!Compress(compressor, body, &builder)) { return std::nullopt; } + return builder.DestructiveGet(); } -bool Compress(Compressor *compressor, Slice body, - NoncontiguousBufferBuilder *builder) { - if (!compressor) { - TILE_LOG_WARNING_EVERY_SECOND("Compressor nullptr"); - return false; - } +bool +Compress(Compressor *compressor, const NoncontiguousBuffer &nb, NoncontiguousBufferBuilder *builder) +{ + if (!compressor) { + TILE_LOG_WARNING_EVERY_SECOND("Compressor nullptr"); + return false; + } - NoncontiguousBufferCompressionOutputStream out(builder); - return compressor->Compress(body.data(), body.size(), &out); + NoncontiguousBufferCompressionOutputStream out(builder); + return compressor->Compress(nb, &out); } -std::optional Decompress(Decompressor *decompressor, - const NoncontiguousBuffer &body) { - NoncontiguousBufferBuilder builder; - if (!Decompress(decompressor, body, &builder)) { - return std::nullopt; - } - return builder.DestructiveGet(); -} -std::optional Decompress(Decompressor *decompressor, - Slice body) { - NoncontiguousBufferBuilder builder; - if (!Decompress(decompressor, body, &builder)) { - return std::nullopt; - } - return builder.DestructiveGet(); +bool +Compress(Compressor *compressor, Slice body, NoncontiguousBufferBuilder *builder) +{ + if (!compressor) { + TILE_LOG_WARNING_EVERY_SECOND("Compressor nullptr"); + return false; + } + + NoncontiguousBufferCompressionOutputStream out(builder); + return compressor->Compress(body.data(), body.size(), &out); } -bool Decompress(Decompressor *decompressor, const NoncontiguousBuffer &nb, - NoncontiguousBufferBuilder *builder) { - if (!decompressor) { - TILE_LOG_WARNING_EVERY_SECOND("Decompressor nullptr"); - return false; - } - - NoncontiguousBufferCompressionOutputStream out(builder); - return decompressor->Decompress(nb, &out); -} -bool Decompress(Decompressor *decompressor, Slice body, - NoncontiguousBufferBuilder *builder) { - if (!decompressor) { - TILE_LOG_WARNING_EVERY_SECOND("Decompressor nullptr"); - return false; - } - - NoncontiguousBufferCompressionOutputStream out(builder); - return decompressor->Decompress(body.data(), body.size(), &out); +std::optional +Decompress(Decompressor *decompressor, const NoncontiguousBuffer &body) +{ + NoncontiguousBufferBuilder builder; + if (!Decompress(decompressor, body, &builder)) { return std::nullopt; } + return builder.DestructiveGet(); } -} // namespace tile +std::optional +Decompress(Decompressor *decompressor, Slice body) +{ + NoncontiguousBufferBuilder builder; + if (!Decompress(decompressor, body, &builder)) { return std::nullopt; } + return builder.DestructiveGet(); +} + +bool +Decompress(Decompressor *decompressor, const NoncontiguousBuffer &nb, NoncontiguousBufferBuilder *builder) +{ + if (!decompressor) { + TILE_LOG_WARNING_EVERY_SECOND("Decompressor nullptr"); + return false; + } + + NoncontiguousBufferCompressionOutputStream out(builder); + return decompressor->Decompress(nb, &out); +} + +bool +Decompress(Decompressor *decompressor, Slice body, NoncontiguousBufferBuilder *builder) +{ + if (!decompressor) { + TILE_LOG_WARNING_EVERY_SECOND("Decompressor nullptr"); + return false; + } + + NoncontiguousBufferCompressionOutputStream out(builder); + return decompressor->Decompress(body.data(), body.size(), &out); +} + +}// namespace tile diff --git a/tile/base/compression.h b/tile/base/compression.h index e325715..cbc1c99 100644 --- a/tile/base/compression.h +++ b/tile/base/compression.h @@ -11,26 +11,19 @@ namespace tile { std::unique_ptr MakeDecompressor(Slice name); std::unique_ptr MakeCompressor(Slice name); -std::optional Compress(Compressor *compressor, - const NoncontiguousBuffer &nb); +std::optional Compress(Compressor *compressor, const NoncontiguousBuffer &nb); std::optional Compress(Compressor *compressor, Slice body); -bool Compress(Compressor *compressor, const NoncontiguousBuffer &nb, - NoncontiguousBufferBuilder *builder); +bool Compress(Compressor *compressor, const NoncontiguousBuffer &nb, NoncontiguousBufferBuilder *builder); -bool Compress(Compressor *compressor, Slice body, - NoncontiguousBufferBuilder *builder); +bool Compress(Compressor *compressor, Slice body, NoncontiguousBufferBuilder *builder); -std::optional Decompress(Decompressor *decompressor, - const NoncontiguousBuffer &body); -std::optional Decompress(Decompressor *decompressor, - Slice body); +std::optional Decompress(Decompressor *decompressor, const NoncontiguousBuffer &body); +std::optional Decompress(Decompressor *decompressor, Slice body); -bool Decompress(Decompressor *decompressor, const NoncontiguousBuffer &nb, - NoncontiguousBufferBuilder *builder); -bool Decompress(Decompressor *decompressor, Slice body, - NoncontiguousBufferBuilder *builder); +bool Decompress(Decompressor *decompressor, const NoncontiguousBuffer &nb, NoncontiguousBufferBuilder *builder); +bool Decompress(Decompressor *decompressor, Slice body, NoncontiguousBufferBuilder *builder); -} // namespace tile +}// namespace tile -#endif // TILE_BASE_COMPRESSION_H +#endif// TILE_BASE_COMPRESSION_H diff --git a/tile/base/compression/compression.cc b/tile/base/compression/compression.cc index 35d6702..072bc7f 100644 --- a/tile/base/compression/compression.cc +++ b/tile/base/compression/compression.cc @@ -4,25 +4,33 @@ namespace tile { TILE_DEFINE_CLASS_DEPENDENCY_REGISTRY(compressor_registry, Compressor); TILE_DEFINE_CLASS_DEPENDENCY_REGISTRY(decompressor_registry, Decompressor); -TestCompressionOutputStream::TestCompressionOutputStream(std::string *s, - std::size_t every_size) - : buffer_(s), every_size_(every_size) {} +TestCompressionOutputStream::TestCompressionOutputStream(std::string *s, std::size_t every_size) + : buffer_(s), + every_size_(every_size) +{} -bool TestCompressionOutputStream::Next(void **data, - std::size_t *size) noexcept { - if (buffer_->size() < using_bytes_ + every_size_) { - buffer_->resize(using_bytes_ + every_size_); - } +bool +TestCompressionOutputStream::Next(void **data, std::size_t *size) noexcept +{ + if (buffer_->size() < using_bytes_ + every_size_) { buffer_->resize(using_bytes_ + every_size_); } - *data = internal::RemoveConstPtr(buffer_->data()) + using_bytes_; - *size = every_size_; + *data = internal::RemoveConstPtr(buffer_->data()) + using_bytes_; + *size = every_size_; - using_bytes_ += every_size_; - return true; + using_bytes_ += every_size_; + return true; } -void TestCompressionOutputStream::BackUp(std::size_t count) noexcept { - using_bytes_ -= count; -} -void TestCompressionOutputStream::Flush() { buffer_->resize(using_bytes_); } -} // namespace tile +void +TestCompressionOutputStream::BackUp(std::size_t count) noexcept +{ + using_bytes_ -= count; +} + +void +TestCompressionOutputStream::Flush() +{ + buffer_->resize(using_bytes_); +} + +}// namespace tile diff --git a/tile/base/compression/compression.h b/tile/base/compression/compression.h index c33d5e2..1d4546d 100644 --- a/tile/base/compression/compression.h +++ b/tile/base/compression/compression.h @@ -9,57 +9,50 @@ namespace tile { class CompressionOutputStream { public: - virtual ~CompressionOutputStream() = default; - // Get a buffer to write to. The buffer may be backed by multiple - virtual bool Next(void **data, std::size_t *size) noexcept = 0; - virtual void BackUp(std::size_t count) noexcept = 0; + virtual ~CompressionOutputStream() = default; + // Get a buffer to write to. The buffer may be backed by multiple + virtual bool Next(void **data, std::size_t *size) noexcept = 0; + virtual void BackUp(std::size_t count) noexcept = 0; }; class Compressor { public: - virtual ~Compressor() = default; - virtual bool Compress(const void *src, std::size_t size, - CompressionOutputStream *out) = 0; - virtual bool Compress(const NoncontiguousBuffer &src, - CompressionOutputStream *out) = 0; + virtual ~Compressor() = default; + virtual bool Compress(const void *src, std::size_t size, CompressionOutputStream *out) = 0; + virtual bool Compress(const NoncontiguousBuffer &src, CompressionOutputStream *out) = 0; }; class Decompressor { public: - ~Decompressor() = default; - virtual bool Decompress(const void *src, std::size_t size, - CompressionOutputStream *out) = 0; - virtual bool Decompress(const NoncontiguousBuffer &src, - CompressionOutputStream *out) = 0; + ~Decompressor() = default; + virtual bool Decompress(const void *src, std::size_t size, CompressionOutputStream *out) = 0; + virtual bool Decompress(const NoncontiguousBuffer &src, CompressionOutputStream *out) = 0; }; TILE_DECLARE_CLASS_DEPENDENCY_REGISTRY(compressor_registry, Compressor); TILE_DECLARE_CLASS_DEPENDENCY_REGISTRY(decompressor_registry, Decompressor); -} // namespace tile +}// namespace tile -#define TILE_COMPRESSION_REGISTER_COMPRESSOR(Name, Implementation) \ - TILE_REGISTER_CLASS_DEPENDENCY(::tile::compressor_registry, Name, \ - Implementation) -#define TILE_COMPRESSION_REGISTER_DECOMPRESSOR(Name, Implementation) \ - TILE_REGISTER_CLASS_DEPENDENCY(::tile::decompressor_registry, Name, \ - Implementation) +#define TILE_COMPRESSION_REGISTER_COMPRESSOR(Name, Implementation) \ + TILE_REGISTER_CLASS_DEPENDENCY(::tile::compressor_registry, Name, Implementation) +#define TILE_COMPRESSION_REGISTER_DECOMPRESSOR(Name, Implementation) \ + TILE_REGISTER_CLASS_DEPENDENCY(::tile::decompressor_registry, Name, Implementation) namespace tile { class TestCompressionOutputStream : public CompressionOutputStream { public: - explicit TestCompressionOutputStream(std::string *s, - std::size_t every_size = 2); + explicit TestCompressionOutputStream(std::string *s, std::size_t every_size = 2); - bool Next(void **data, std::size_t *size) noexcept override; - void BackUp(std::size_t count) noexcept override; - void Flush(); + bool Next(void **data, std::size_t *size) noexcept override; + void BackUp(std::size_t count) noexcept override; + void Flush(); private: - std::size_t using_bytes_{}; - std::size_t every_size_; - std::string *buffer_; + std::size_t using_bytes_{}; + std::size_t every_size_; + std::string *buffer_; }; -} // namespace tile +}// namespace tile -#endif // TILE_BASE_COMPRESSION_COMPRESSION_H +#endif// TILE_BASE_COMPRESSION_COMPRESSION_H diff --git a/tile/base/compression/gzip.cc b/tile/base/compression/gzip.cc index 3041d88..3d4331f 100644 --- a/tile/base/compression/gzip.cc +++ b/tile/base/compression/gzip.cc @@ -11,24 +11,28 @@ TILE_COMPRESSION_REGISTER_DECOMPRESSOR("gzip", GzipDecompressor); namespace detail { struct ZStream { - z_stream stream; + z_stream stream; }; -} // namespace detail +}// namespace detail + namespace { -inline double EstimateCompressionRate(const z_stream *stream, - double default_value) { - if (stream->total_in > 0) { - double rate = 1.0f * stream->total_out / stream->total_in; - constexpr double kMinRate = 1.1; - return rate * kMinRate; - } +inline double +EstimateCompressionRate(const z_stream *stream, double default_value) +{ + if (stream->total_in > 0) { + double rate = 1.0f * stream->total_out / stream->total_in; + constexpr double kMinRate = 1.1; + return rate * kMinRate; + } - return default_value; + return default_value; } -inline uint32_t RestrictAvailSize(size_t size) { - return static_cast(std::min(size, static_cast(UINT32_MAX))); +inline uint32_t +RestrictAvailSize(size_t size) +{ + return static_cast(std::min(size, static_cast(UINT32_MAX))); } // See document of inflateInit2 in zlib.h @@ -37,207 +41,223 @@ constexpr int ZLIB_INIT_FLAG_GZIP = 16; // he size to increase every time Z_BUF_ERROR returns. constexpr int kOutBufferIncreaseSize = 32; -bool DoAppend(z_stream *stream, CompressionOutputStream *out_stream, - const void *input_buffer, std::size_t input_size, bool is_deflate, - bool finish) { - TILE_CHECK(stream && out_stream); +bool +DoAppend(z_stream *stream, + CompressionOutputStream *out_stream, + const void *input_buffer, + std::size_t input_size, + bool is_deflate, + bool finish) +{ + TILE_CHECK(stream && out_stream); - if (!finish && (input_buffer == nullptr || input_size == 0)) { - // no input data - return true; - } + if (!finish && (input_buffer == nullptr || input_size == 0)) { + // no input data + return true; + } - stream->next_in = reinterpret_cast(const_cast(input_buffer)); - int code = Z_OK; - // the number of `buffer too small error` - int need_more_space_cnt = 0; - std::string tmp_buffer; - size_t left_size = input_size; - while (left_size > 0 || need_more_space_cnt > 0 || finish) { - stream->avail_in = RestrictAvailSize(left_size); - const auto current_avail_in = stream->avail_in; - std::size_t out_size; - if (!need_more_space_cnt) { - void *out_data; - if (!out_stream->Next(&out_data, &out_size)) { - // out buffer is full - return false; - } + stream->next_in = reinterpret_cast(const_cast(input_buffer)); + int code = Z_OK; + // the number of `buffer too small error` + int need_more_space_cnt = 0; + std::string tmp_buffer; + size_t left_size = input_size; + while (left_size > 0 || need_more_space_cnt > 0 || finish) { + stream->avail_in = RestrictAvailSize(left_size); + const auto current_avail_in = stream->avail_in; + std::size_t out_size; + if (!need_more_space_cnt) { + void *out_data; + if (!out_stream->Next(&out_data, &out_size)) { + // out buffer is full + return false; + } - stream->next_out = reinterpret_cast(out_data); + stream->next_out = reinterpret_cast(out_data); + } else { + double rate = EstimateCompressionRate(stream, 0.5); + tmp_buffer.resize(left_size * rate + need_more_space_cnt * kOutBufferIncreaseSize); + stream->next_out = reinterpret_cast(internal::RemoveConstPtr(tmp_buffer.data())); + out_size = tmp_buffer.size(); + } + + stream->avail_out = RestrictAvailSize(out_size); + const std::size_t current_avail_out = stream->avail_out; + + TILE_CHECK_GT(stream->avail_out, 0, "Avail_out should never be zero before the call."); + int flush_option = finish ? Z_FINISH : Z_NO_FLUSH; + if (is_deflate) { + code = deflate(stream, flush_option); + } else { + code = inflate(stream, flush_option); + } + + // https://refspecs.linuxbase.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/zlib-inflate-1.html + // No progress is possible; either avail_in or avail_out was zero. + if (code == Z_BUF_ERROR) { + if (need_more_space_cnt == 0) { out_stream->BackUp(out_size); } + + if (stream->avail_in == 0) { + // if not finish, we need more input data + // otherwise, fail to compress/decompress + return !finish; + } + + ++need_more_space_cnt; + continue; + } + + if (code < 0) { + TILE_LOG_ERROR_EVERY_SECOND("gzip compress error code [{}]", code); + break; + } + + // consume input data (current_avail_in - stream->avail_in) + // produce output data (stream->avail_out) + left_size -= current_avail_in - stream->avail_in; + if (need_more_space_cnt == 0) { + out_stream->BackUp(stream->avail_out); + } else { + if (TILE_UNLIKELY(!CopyDataToCompressionOutputStream( + out_stream, tmp_buffer.data(), current_avail_out - stream->avail_out))) { + return false; + } + need_more_space_cnt = 0; + } + + if (code == Z_STREAM_END) { return true; } + } + + return code == Z_OK; +} +}// namespace + +bool +GzipCompressor::Compress(const void *src, std::size_t size, CompressionOutputStream *out) +{ + bool ok = Init(out); + ok &= Append(src, size); + ok &= Flush(); + out_ = nullptr; + return ok; +} + +bool +GzipCompressor::Compress(const NoncontiguousBuffer &bytes, CompressionOutputStream *out) +{ + bool ok = Init(out); + std::size_t left = bytes.ByteSize(); + for (auto iter = bytes.begin(); ok && iter != bytes.end(); ++iter) { + auto len = std::min(left, iter->size()); + ok &= Append(iter->data(), len); + left -= len; + } + ok &= Flush(); + out_ = nullptr; + return ok; +} + +bool +GzipCompressor::Append(const void *buffer, std::size_t size) +{ + return DoAppend(&stream_->stream, out_, buffer, size, true, false); +} + +bool +GzipCompressor::Flush() +{ + TILE_CHECK(out_); + if (!DoAppend(&stream_->stream, out_, nullptr, 0, true, true)) { return false; } + return Release(); +} + +bool +GzipCompressor::Init(CompressionOutputStream *out) +{ + TILE_CHECK(!out_); + stream_ = make_unique(); + int code = deflateInit2( + &stream_->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + ZLIB_INIT_FLAG_GZIP, 8, Z_DEFAULT_STRATEGY); + if (code != Z_OK) { + TILE_LOG_ERROR_EVERY_SECOND("deflateInit2 error code [{}]", code); + stream_ = nullptr; } else { - double rate = EstimateCompressionRate(stream, 0.5); - tmp_buffer.resize(left_size * rate + - need_more_space_cnt * kOutBufferIncreaseSize); - stream->next_out = reinterpret_cast( - internal::RemoveConstPtr(tmp_buffer.data())); - out_size = tmp_buffer.size(); + out_ = out; } + return code == Z_OK; +} - stream->avail_out = RestrictAvailSize(out_size); - const std::size_t current_avail_out = stream->avail_out; +bool +GzipCompressor::Release() +{ + TILE_CHECK(stream_); + int code = deflateEnd(&stream_->stream); + if (code != Z_OK) { TILE_LOG_WARNING_EVERY_SECOND("DeflateEnd fail with code [{}].", code); } + return code == Z_OK; +} - TILE_CHECK_GT(stream->avail_out, 0, - "Avail_out should never be zero before the call."); - int flush_option = finish ? Z_FINISH : Z_NO_FLUSH; - if (is_deflate) { - code = deflate(stream, flush_option); +bool +GzipDecompressor::Decompress(const void *src, std::size_t size, CompressionOutputStream *out) +{ + bool ok = Init(out); + ok &= Append(src, size); + ok &= Flush(); + out_ = nullptr; + return ok; +} + +bool +GzipDecompressor::Decompress(const NoncontiguousBuffer &compressed, CompressionOutputStream *out) +{ + bool ok = Init(out); + std::size_t left = compressed.ByteSize(); + for (auto iter = compressed.begin(); ok && iter != compressed.end(); ++iter) { + auto len = std::min(left, iter->size()); + ok &= Append(iter->data(), len); + left -= len; + } + ok &= Flush(); + out_ = nullptr; + return ok; +} + +bool +GzipDecompressor::Append(const void *buffer, std::size_t size) +{ + return DoAppend(&stream_->stream, out_, buffer, size, false, false); +} + +bool +GzipDecompressor::Flush() +{ + TILE_CHECK(out_); + if (!DoAppend(&stream_->stream, out_, nullptr, 0, false, true)) { return false; } + return Release(); +} + +bool +GzipDecompressor::Init(CompressionOutputStream *out) +{ + TILE_CHECK(!out_); + stream_ = make_unique(); + int code = inflateInit2(&stream_->stream, MAX_WBITS + ZLIB_INIT_FLAG_GZIP); + if (code != Z_OK) { + TILE_LOG_ERROR_EVERY_SECOND("inflateInit2 error code [{}]", code); + stream_ = nullptr; } else { - code = inflate(stream, flush_option); + out_ = out; } - - // https://refspecs.linuxbase.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/zlib-inflate-1.html - // No progress is possible; either avail_in or avail_out was zero. - if (code == Z_BUF_ERROR) { - if (need_more_space_cnt == 0) { - out_stream->BackUp(out_size); - } - - if (stream->avail_in == 0) { - // if not finish, we need more input data - // otherwise, fail to compress/decompress - return !finish; - } - - ++need_more_space_cnt; - continue; - } - - if (code < 0) { - TILE_LOG_ERROR_EVERY_SECOND("gzip compress error code [{}]", code); - break; - } - - // consume input data (current_avail_in - stream->avail_in) - // produce output data (stream->avail_out) - left_size -= current_avail_in - stream->avail_in; - if (need_more_space_cnt == 0) { - out_stream->BackUp(stream->avail_out); - } else { - if (TILE_UNLIKELY(!CopyDataToCompressionOutputStream( - out_stream, tmp_buffer.data(), - current_avail_out - stream->avail_out))) { - return false; - } - need_more_space_cnt = 0; - } - - if (code == Z_STREAM_END) { - return true; - } - } - - return code == Z_OK; -} -} // namespace - -bool GzipCompressor::Compress(const void *src, std::size_t size, - CompressionOutputStream *out) { - bool ok = Init(out); - ok &= Append(src, size); - ok &= Flush(); - out_ = nullptr; - return ok; -} -bool GzipCompressor::Compress(const NoncontiguousBuffer &bytes, - CompressionOutputStream *out) { - bool ok = Init(out); - std::size_t left = bytes.ByteSize(); - for (auto iter = bytes.begin(); ok && iter != bytes.end(); ++iter) { - auto len = std::min(left, iter->size()); - ok &= Append(iter->data(), len); - left -= len; - } - ok &= Flush(); - out_ = nullptr; - return ok; -} -bool GzipCompressor::Append(const void *buffer, std::size_t size) { - return DoAppend(&stream_->stream, out_, buffer, size, true, false); -} -bool GzipCompressor::Flush() { - TILE_CHECK(out_); - if (!DoAppend(&stream_->stream, out_, nullptr, 0, true, true)) { - return false; - } - return Release(); + return code == Z_OK; } -bool GzipCompressor::Init(CompressionOutputStream *out) { - TILE_CHECK(!out_); - stream_ = make_unique(); - int code = - deflateInit2(&stream_->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, - MAX_WBITS + ZLIB_INIT_FLAG_GZIP, 8, Z_DEFAULT_STRATEGY); - if (code != Z_OK) { - TILE_LOG_ERROR_EVERY_SECOND("deflateInit2 error code [{}]", code); - stream_ = nullptr; - } else { - out_ = out; - } - return code == Z_OK; -} -bool GzipCompressor::Release() { - TILE_CHECK(stream_); - int code = deflateEnd(&stream_->stream); - if (code != Z_OK) { - TILE_LOG_WARNING_EVERY_SECOND("DeflateEnd fail with code [{}].", code); - } - return code == Z_OK; +bool +GzipDecompressor::Release() +{ + TILE_CHECK(stream_); + int code = inflateEnd(&stream_->stream); + if (code != Z_OK) { TILE_LOG_WARNING_EVERY_SECOND("DeflateEnd fail with code [{}].", code); } + return code == Z_OK; } -bool GzipDecompressor::Decompress(const void *src, std::size_t size, - CompressionOutputStream *out) { - bool ok = Init(out); - ok &= Append(src, size); - ok &= Flush(); - out_ = nullptr; - return ok; -} -bool GzipDecompressor::Decompress(const NoncontiguousBuffer &compressed, - CompressionOutputStream *out) { - bool ok = Init(out); - std::size_t left = compressed.ByteSize(); - for (auto iter = compressed.begin(); ok && iter != compressed.end(); ++iter) { - auto len = std::min(left, iter->size()); - ok &= Append(iter->data(), len); - left -= len; - } - ok &= Flush(); - out_ = nullptr; - return ok; -} - -bool GzipDecompressor::Append(const void *buffer, std::size_t size) { - return DoAppend(&stream_->stream, out_, buffer, size, false, false); -} -bool GzipDecompressor::Flush() { - TILE_CHECK(out_); - if (!DoAppend(&stream_->stream, out_, nullptr, 0, false, true)) { - return false; - } - return Release(); -} -bool GzipDecompressor::Init(CompressionOutputStream *out) { - TILE_CHECK(!out_); - stream_ = make_unique(); - int code = inflateInit2(&stream_->stream, MAX_WBITS + ZLIB_INIT_FLAG_GZIP); - if (code != Z_OK) { - TILE_LOG_ERROR_EVERY_SECOND("inflateInit2 error code [{}]", code); - stream_ = nullptr; - } else { - out_ = out; - } - return code == Z_OK; -} -bool GzipDecompressor::Release() { - TILE_CHECK(stream_); - int code = inflateEnd(&stream_->stream); - if (code != Z_OK) { - TILE_LOG_WARNING_EVERY_SECOND("DeflateEnd fail with code [{}].", code); - } - return code == Z_OK; -} - -} // namespace compression -} // namespace tile +}// namespace compression +}// namespace tile diff --git a/tile/base/compression/gzip.h b/tile/base/compression/gzip.h index 6340752..2d7d18a 100644 --- a/tile/base/compression/gzip.h +++ b/tile/base/compression/gzip.h @@ -5,48 +5,43 @@ #include - #include "tile/base/compression/compression.h" namespace tile { namespace compression { namespace detail { struct ZStream; -} // namespace detail +}// namespace detail class GzipCompressor : public Compressor { public: - bool Compress(const void *src, std::size_t size, - CompressionOutputStream *out) override; - bool Compress(const NoncontiguousBuffer &bytes, - CompressionOutputStream *out) override; + bool Compress(const void *src, std::size_t size, CompressionOutputStream *out) override; + bool Compress(const NoncontiguousBuffer &bytes, CompressionOutputStream *out) override; private: - bool Append(const void *buffer, std::size_t size); - bool Flush(); - bool Init(CompressionOutputStream *out); - bool Release(); - std::unique_ptr stream_; - CompressionOutputStream *out_ = nullptr; + bool Append(const void *buffer, std::size_t size); + bool Flush(); + bool Init(CompressionOutputStream *out); + bool Release(); + std::unique_ptr stream_; + CompressionOutputStream *out_ = nullptr; }; class GzipDecompressor : public Decompressor { public: - bool Decompress(const void *src, std::size_t size, - CompressionOutputStream *out) override; - bool Decompress(const NoncontiguousBuffer &compressed, - CompressionOutputStream *out) override; + bool Decompress(const void *src, std::size_t size, CompressionOutputStream *out) override; + bool Decompress(const NoncontiguousBuffer &compressed, CompressionOutputStream *out) override; private: - bool Append(const void *buffer, std::size_t size); - bool Flush(); - bool Init(CompressionOutputStream *out); - bool Release(); - std::unique_ptr stream_; - CompressionOutputStream *out_ = nullptr; + bool Append(const void *buffer, std::size_t size); + bool Flush(); + bool Init(CompressionOutputStream *out); + bool Release(); + std::unique_ptr stream_; + CompressionOutputStream *out_ = nullptr; }; -} // namespace compression -} // namespace tile +}// namespace compression +}// namespace tile -#endif // TILE_BASE_COMPRESSION_GZIP_H +#endif// TILE_BASE_COMPRESSION_GZIP_H diff --git a/tile/base/compression/util.cc b/tile/base/compression/util.cc index ae021b0..3d2c0ec 100644 --- a/tile/base/compression/util.cc +++ b/tile/base/compression/util.cc @@ -1,37 +1,33 @@ #include "util.h" + namespace tile { namespace compression { -bool CopyDataToCompressionOutputStream(CompressionOutputStream *out, - const void *data, std::size_t size) { +bool +CopyDataToCompressionOutputStream(CompressionOutputStream *out, const void *data, std::size_t size) +{ - if (size == 0) { - return true; - } + if (size == 0) { return true; } - std::size_t current_pos = 0; - std::size_t left_to_copy = size; + std::size_t current_pos = 0; + std::size_t left_to_copy = size; - while (true) { - void *next_data; - std::size_t next_size; - if (TILE_UNLIKELY(!out->Next(&next_data, &next_size))) { - return false; + while (true) { + void *next_data; + std::size_t next_size; + if (TILE_UNLIKELY(!out->Next(&next_data, &next_size))) { return false; } + + if (left_to_copy <= next_size) { + memcpy(next_data, reinterpret_cast(data) + current_pos, left_to_copy); + out->BackUp(next_size - left_to_copy); + return true; + } else { + memcpy(next_data, reinterpret_cast(data) + current_pos, next_size); + current_pos += next_size; + left_to_copy -= next_size; + } } - - if (left_to_copy <= next_size) { - memcpy(next_data, reinterpret_cast(data) + current_pos, - left_to_copy); - out->BackUp(next_size - left_to_copy); - return true; - } else { - memcpy(next_data, reinterpret_cast(data) + current_pos, - next_size); - current_pos += next_size; - left_to_copy -= next_size; - } - } - TILE_UNREACHABLE(""); - return false; + TILE_UNREACHABLE(""); + return false; } -} // namespace compression -} // namespace tile +}// namespace compression +}// namespace tile diff --git a/tile/base/compression/util.h b/tile/base/compression/util.h index ea14542..21aaad0 100644 --- a/tile/base/compression/util.h +++ b/tile/base/compression/util.h @@ -7,9 +7,8 @@ namespace tile { namespace compression { -bool CopyDataToCompressionOutputStream(CompressionOutputStream *out, - const void *data, std::size_t size); +bool CopyDataToCompressionOutputStream(CompressionOutputStream *out, const void *data, std::size_t size); } -} // namespace tile +}// namespace tile -#endif // TILE_BASE_COMPRESSION_UTIL_H +#endif// TILE_BASE_COMPRESSION_UTIL_H diff --git a/tile/base/compression/util_test.cc b/tile/base/compression/util_test.cc index 232bea7..ac75e09 100644 --- a/tile/base/compression/util_test.cc +++ b/tile/base/compression/util_test.cc @@ -4,19 +4,20 @@ namespace tile { namespace compression { -TEST(CopyDataToCompressionOutputStream, All) { - std::string s; - std::string a = "123456789+"; +TEST(CopyDataToCompressionOutputStream, All) +{ + std::string s; + std::string a = "123456789+"; - TestCompressionOutputStream out1(&s, 2); - CopyDataToCompressionOutputStream(&out1, a.data(), 1); - CopyDataToCompressionOutputStream(&out1, a.data() + 1, 2); - CopyDataToCompressionOutputStream(&out1, a.data() + 3, 3); - CopyDataToCompressionOutputStream(&out1, a.data() + 6, 4); - out1.Flush(); + TestCompressionOutputStream out1(&s, 2); + CopyDataToCompressionOutputStream(&out1, a.data(), 1); + CopyDataToCompressionOutputStream(&out1, a.data() + 1, 2); + CopyDataToCompressionOutputStream(&out1, a.data() + 3, 3); + CopyDataToCompressionOutputStream(&out1, a.data() + 6, 4); + out1.Flush(); - ASSERT_EQ(s, a); + ASSERT_EQ(s, a); } -} // namespace compression +}// namespace compression -} // namespace tile +}// namespace tile diff --git a/tile/base/compression_test.cc b/tile/base/compression_test.cc index 084140b..77d814b 100644 --- a/tile/base/compression_test.cc +++ b/tile/base/compression_test.cc @@ -11,62 +11,67 @@ static const char *algos[] = { "gzip", }; } -TEST(MakeCompressor, All) { - auto &&c = MakeCompressor("gzip"); - EXPECT_TRUE(c); - c = MakeCompressor("??"); - EXPECT_FALSE(c); + +TEST(MakeCompressor, All) +{ + auto &&c = MakeCompressor("gzip"); + EXPECT_TRUE(c); + c = MakeCompressor("??"); + EXPECT_FALSE(c); } -TEST(MakeDecompressor, All) { - auto &&c = MakeDecompressor("gzip"); - EXPECT_TRUE(c); - c = MakeDecompressor("??"); - EXPECT_FALSE(c); +TEST(MakeDecompressor, All) +{ + auto &&c = MakeDecompressor("gzip"); + EXPECT_TRUE(c); + c = MakeDecompressor("??"); + EXPECT_FALSE(c); } -TEST(CompressString, All) { - std::string original(1000, 'A'); - auto c = Compress(MakeCompressor("gzip").get(), original); - EXPECT_TRUE(c); - auto d = Decompress(MakeDecompressor("gzip").get(), *c); - EXPECT_TRUE(d); - EXPECT_EQ(FlattenSlow(*d), original); +TEST(CompressString, All) +{ + std::string original(1000, 'A'); + auto c = Compress(MakeCompressor("gzip").get(), original); + EXPECT_TRUE(c); + auto d = Decompress(MakeDecompressor("gzip").get(), *c); + EXPECT_TRUE(d); + EXPECT_EQ(FlattenSlow(*d), original); } -TEST(CompressNoncontiguousBuffer, All) { - NoncontiguousBufferBuilder nbb; - std::string original(1000, 'A'); - nbb.Append(original.data(), original.size()); - auto &&nb = nbb.DestructiveGet(); - auto c = Compress(MakeCompressor("gzip").get(), nb); - EXPECT_TRUE(c); - auto d = Decompress(MakeDecompressor("gzip").get(), *c); - EXPECT_TRUE(d); - EXPECT_EQ(FlattenSlow(*d), original); +TEST(CompressNoncontiguousBuffer, All) +{ + NoncontiguousBufferBuilder nbb; + std::string original(1000, 'A'); + nbb.Append(original.data(), original.size()); + auto &&nb = nbb.DestructiveGet(); + auto c = Compress(MakeCompressor("gzip").get(), nb); + EXPECT_TRUE(c); + auto d = Decompress(MakeDecompressor("gzip").get(), *c); + EXPECT_TRUE(d); + EXPECT_EQ(FlattenSlow(*d), original); } -TEST(Decompressor, Empty) { - for (auto &&algo : algos) { - auto res = Decompress(MakeDecompressor(algo).get(), ""); +TEST(Decompressor, Empty) +{ + for (auto &&algo : algos) { + auto res = Decompress(MakeDecompressor(algo).get(), ""); - // Failure in decompressing empty buffer is not an error. So long as - // decompressing a buffer produced by `Compress(..., "")` works correctly, - // we're fine. - if (res) { - // However, if the decompression does succeed, the resulting buffer should - // be empty. - EXPECT_TRUE(res->Empty()); + // Failure in decompressing empty buffer is not an error. So long as + // decompressing a buffer produced by `Compress(..., "")` works correctly, + // we're fine. + if (res) { + // However, if the decompression does succeed, the resulting buffer should + // be empty. + EXPECT_TRUE(res->Empty()); + } } - } } -TEST(Decompressor, Invalid) { - for (auto &&algo : algos) { - auto res = - Decompress(MakeDecompressor(algo).get(), - "this buffer is likely an invalid compressed buffer."); - EXPECT_FALSE(res); - } +TEST(Decompressor, Invalid) +{ + for (auto &&algo : algos) { + auto res = Decompress(MakeDecompressor(algo).get(), "this buffer is likely an invalid compressed buffer."); + EXPECT_FALSE(res); + } } -} // namespace tile +}// namespace tile diff --git a/tile/base/config/configurable.h b/tile/base/config/configurable.h index ddbca56..99918b2 100644 --- a/tile/base/config/configurable.h +++ b/tile/base/config/configurable.h @@ -6,12 +6,12 @@ namespace tile { class Configurable { - Configurable(); - virtual ~Configurable() = default; - virtual void SetProperty(const Slice &name, const Slice &value) = 0; - virtual std::string GetProperty(const Slice &name) const = 0; + Configurable(); + virtual ~Configurable() = default; + virtual void SetProperty(const Slice &name, const Slice &value) = 0; + virtual std::string GetProperty(const Slice &name) const = 0; }; -} // namespace tile +}// namespace tile -#endif // TILE_BASE_CONFIG_CONFIGURABLE_H +#endif// TILE_BASE_CONFIG_CONFIGURABLE_H diff --git a/tile/base/config/configuration.cc b/tile/base/config/configuration.cc index dd921b0..6f2999b 100644 --- a/tile/base/config/configuration.cc +++ b/tile/base/config/configuration.cc @@ -4,80 +4,99 @@ #include "tile/base/thread/unique_lock.h" namespace tile { -bool Configuration::Has(const Slice &key) const { - UniqueLock lock(mutex_); - std::string value; - return GetRaw(key, &value); +bool +Configuration::Has(const Slice &key) const +{ + UniqueLock lock(mutex_); + std::string value; + return GetRaw(key, &value); } -void Configuration::Remove(const Slice &key) { - UniqueLock lock(mutex_); - if (events_enabled_) { - OnRemoving(key); - } - RemoveRaw(key); - if (events_enabled_) { - OnRemoved(key); - } +void +Configuration::Remove(const Slice &key) +{ + UniqueLock lock(mutex_); + if (events_enabled_) { OnRemoving(key); } + RemoveRaw(key); + if (events_enabled_) { OnRemoved(key); } } -void Configuration::EnableEvents(bool enable) { events_enabled_ = enable; } -bool Configuration::EventsEnabled() const { return events_enabled_; } - -Configuration::Keys Configuration::keys(const Slice &root) const { - UniqueLock lock(mutex_); - return Enumerate(root); +void +Configuration::EnableEvents(bool enable) +{ + events_enabled_ = enable; } -#define TILE_DEFINE_CONFIG_GETTER(type, name) \ - std::optional Configuration::Get##name(const Slice &key) const { \ - std::string value; \ - if (GetRaw(key, &value)) { \ - auto opt = TryParseTraits::TryParse(value); \ - if (opt.has_value()) { \ - return *opt; \ - } else { \ - return std::nullopt; \ - } \ - } else { \ - return std::nullopt; \ - } \ - } \ - type Configuration::Get##name(const Slice &key, type default_value) const { \ - auto opt = Get##name(key); \ - if (opt.has_value()) { \ - return *opt; \ - } else { \ - return default_value; \ - } \ - } - -#define TILE_DEFINE_CONFIG_SETTER(type, name) \ - void Configuration::Set##name(const Slice &key, type value) { \ - SetRawWithEvent(key, Format("{}", value)); \ - } - -std::optional Configuration::GetString(const Slice &key) const { - std::string value; - UniqueLock lock(mutex_); - if (GetRaw(key, &value)) { - return value; - } else { - return std::nullopt; - } +bool +Configuration::EventsEnabled() const +{ + return events_enabled_; } -std::string Configuration::GetString(const Slice &key, - std::string default_value) const { - auto opt = GetString(key); - return opt.has_value() ? *opt : default_value; +Configuration::Keys +Configuration::keys(const Slice &root) const +{ + UniqueLock lock(mutex_); + return Enumerate(root); } -void Configuration::SetString(const Slice &key, const std::string &value) { - SetRawWithEvent(key, value); +#define TILE_DEFINE_CONFIG_GETTER(type, name) \ + std::optional Configuration::Get##name(const Slice &key) const \ + { \ + std::string value; \ + if (GetRaw(key, &value)) { \ + auto opt = TryParseTraits::TryParse(value); \ + if (opt.has_value()) { \ + return *opt; \ + } else { \ + return std::nullopt; \ + } \ + } else { \ + return std::nullopt; \ + } \ + } \ + type Configuration::Get##name(const Slice &key, type default_value) const \ + { \ + auto opt = Get##name(key); \ + if (opt.has_value()) { \ + return *opt; \ + } else { \ + return default_value; \ + } \ + } + +#define TILE_DEFINE_CONFIG_SETTER(type, name) \ + void Configuration::Set##name(const Slice &key, type value) { SetRawWithEvent(key, Format("{}", value)); } + +std::optional +Configuration::GetString(const Slice &key) const +{ + std::string value; + UniqueLock lock(mutex_); + if (GetRaw(key, &value)) { + return value; + } else { + return std::nullopt; + } } -void Configuration::SetBool(const Slice &key, bool value) { - SetRawWithEvent(key, value ? "true" : "false"); + +std::string +Configuration::GetString(const Slice &key, std::string default_value) const +{ + auto opt = GetString(key); + return opt.has_value() ? *opt : default_value; +} + +void +Configuration::SetString(const Slice &key, const std::string &value) +{ + SetRawWithEvent(key, value); +} + +void +Configuration::SetBool(const Slice &key, bool value) +{ + SetRawWithEvent(key, value ? "true" : "false"); } TILE_DEFINE_CONFIG_GETTER(int, Int) @@ -101,22 +120,19 @@ TILE_DEFINE_CONFIG_SETTER(uint32_t, UInt32) TILE_DEFINE_CONFIG_SETTER(uint64_t, UInt64) TILE_DEFINE_CONFIG_SETTER(double, Double) -void Configuration::SetRawWithEvent(const Slice &key, - const std::string &value) { - if (events_enabled_) { - OnChanging(key, value); - } +void +Configuration::SetRawWithEvent(const Slice &key, const std::string &value) +{ + if (events_enabled_) { OnChanging(key, value); } - { - UniqueLock lock(mutex_); - SetRaw(key, value); - } + { + UniqueLock lock(mutex_); + SetRaw(key, value); + } - if (events_enabled_) { - OnChanged(key, value); - } + if (events_enabled_) { OnChanged(key, value); } } Configuration::~Configuration() {} -} // namespace tile +}// namespace tile diff --git a/tile/base/config/configuration.h b/tile/base/config/configuration.h index 4484dad..c595e3b 100644 --- a/tile/base/config/configuration.h +++ b/tile/base/config/configuration.h @@ -12,113 +12,111 @@ namespace tile { class Configuration : public RefCounted { public: - using Keys = std::vector; - using Ptr = RefPtr; + using Keys = std::vector; + using Ptr = RefPtr; - // events - // Key, Value - sigslot::signal2 OnChanging; - // Key, Value - sigslot::signal2 OnChanged; - // Key - sigslot::signal1 OnRemoving; - // Key - sigslot::signal1 OnRemoved; + // events + // Key, Value + sigslot::signal2 OnChanging; + // Key, Value + sigslot::signal2 OnChanged; + // Key + sigslot::signal1 OnRemoving; + // Key + sigslot::signal1 OnRemoved; - bool Has(const Slice &key) const; - void Remove(const Slice &key); - void EnableEvents(bool enable = true); - bool EventsEnabled() const; + bool Has(const Slice &key) const; + void Remove(const Slice &key); + void EnableEvents(bool enable = true); + bool EventsEnabled() const; - Keys keys(const Slice &root = "") const; + Keys keys(const Slice &root = "") const; -#define TILE_DECLARE_CONFIG_GETTER(type, name) \ - std::optional Get##name(const Slice &key) const; \ - type Get##name(const Slice &key, type default_value) const; +#define TILE_DECLARE_CONFIG_GETTER(type, name) \ + std::optional Get##name(const Slice &key) const; \ + type Get##name(const Slice &key, type default_value) const; -#define TILE_DECLARE_CONFIG_SETTER(type, name) \ - virtual void Set##name(const Slice &key, type value); +#define TILE_DECLARE_CONFIG_SETTER(type, name) virtual void Set##name(const Slice &key, type value); - std::string GetRawString(const Slice &key, const Slice &default_value) const; - // std::stirng GetString() - // int GetInt() - // unsigned int GetUInt() - // int16_t GetInt16() - // int32_t GetInt32() - // int64_t GetInt64() - // uint16_t GetUInt16() - // uint32_t GetUInt32() - // uint64_t GetUInt64() - // double GetDouble() - // bool GetBool() + std::string GetRawString(const Slice &key, const Slice &default_value) const; + // std::stirng GetString() + // int GetInt() + // unsigned int GetUInt() + // int16_t GetInt16() + // int32_t GetInt32() + // int64_t GetInt64() + // uint16_t GetUInt16() + // uint32_t GetUInt32() + // uint64_t GetUInt64() + // double GetDouble() + // bool GetBool() - // getters - TILE_DECLARE_CONFIG_GETTER(std::string, String) - TILE_DECLARE_CONFIG_GETTER(int, Int) - TILE_DECLARE_CONFIG_GETTER(unsigned int, UInt) - TILE_DECLARE_CONFIG_GETTER(int16_t, Int16) - TILE_DECLARE_CONFIG_GETTER(int32_t, Int32) - TILE_DECLARE_CONFIG_GETTER(int64_t, Int64) - TILE_DECLARE_CONFIG_GETTER(uint16_t, UInt16) - TILE_DECLARE_CONFIG_GETTER(uint32_t, UInt32) - TILE_DECLARE_CONFIG_GETTER(uint64_t, UInt64) - TILE_DECLARE_CONFIG_GETTER(double, Double) - TILE_DECLARE_CONFIG_GETTER(bool, Bool) + // getters + TILE_DECLARE_CONFIG_GETTER(std::string, String) + TILE_DECLARE_CONFIG_GETTER(int, Int) + TILE_DECLARE_CONFIG_GETTER(unsigned int, UInt) + TILE_DECLARE_CONFIG_GETTER(int16_t, Int16) + TILE_DECLARE_CONFIG_GETTER(int32_t, Int32) + TILE_DECLARE_CONFIG_GETTER(int64_t, Int64) + TILE_DECLARE_CONFIG_GETTER(uint16_t, UInt16) + TILE_DECLARE_CONFIG_GETTER(uint32_t, UInt32) + TILE_DECLARE_CONFIG_GETTER(uint64_t, UInt64) + TILE_DECLARE_CONFIG_GETTER(double, Double) + TILE_DECLARE_CONFIG_GETTER(bool, Bool) protected: - // setters - // SetString(const Slice &key, const std::string &value) - // SetInt(const Slice &key, int value) - // SetUInt(const Slice &key, unsigned int value) - // SetInt16(const Slice &key, int16_t value) - // SetInt32(const Slice &key, int32_t value) - // SetInt64(const Slice &key, int64_t value) - // SetUInt16(const Slice &key, uint16_t value) - // SetUInt32(const Slice &key, uint32_t value) - // SetUInt64(const Slice &key, uint64_t value) - // SetDouble(const Slice &key, double value) - // SetBool(const Slice &key, bool value) - TILE_DECLARE_CONFIG_SETTER(const std::string &, String) - TILE_DECLARE_CONFIG_SETTER(int, Int) - TILE_DECLARE_CONFIG_SETTER(unsigned int, UInt) - TILE_DECLARE_CONFIG_SETTER(int16_t, Int16) - TILE_DECLARE_CONFIG_SETTER(int32_t, Int32) - TILE_DECLARE_CONFIG_SETTER(int64_t, Int64) - TILE_DECLARE_CONFIG_SETTER(uint16_t, UInt16) - TILE_DECLARE_CONFIG_SETTER(uint32_t, UInt32) - TILE_DECLARE_CONFIG_SETTER(uint64_t, UInt64) - TILE_DECLARE_CONFIG_SETTER(double, Double) - TILE_DECLARE_CONFIG_SETTER(bool, Bool) + // setters + // SetString(const Slice &key, const std::string &value) + // SetInt(const Slice &key, int value) + // SetUInt(const Slice &key, unsigned int value) + // SetInt16(const Slice &key, int16_t value) + // SetInt32(const Slice &key, int32_t value) + // SetInt64(const Slice &key, int64_t value) + // SetUInt16(const Slice &key, uint16_t value) + // SetUInt32(const Slice &key, uint32_t value) + // SetUInt64(const Slice &key, uint64_t value) + // SetDouble(const Slice &key, double value) + // SetBool(const Slice &key, bool value) + TILE_DECLARE_CONFIG_SETTER(const std::string &, String) + TILE_DECLARE_CONFIG_SETTER(int, Int) + TILE_DECLARE_CONFIG_SETTER(unsigned int, UInt) + TILE_DECLARE_CONFIG_SETTER(int16_t, Int16) + TILE_DECLARE_CONFIG_SETTER(int32_t, Int32) + TILE_DECLARE_CONFIG_SETTER(int64_t, Int64) + TILE_DECLARE_CONFIG_SETTER(uint16_t, UInt16) + TILE_DECLARE_CONFIG_SETTER(uint32_t, UInt32) + TILE_DECLARE_CONFIG_SETTER(uint64_t, UInt64) + TILE_DECLARE_CONFIG_SETTER(double, Double) + TILE_DECLARE_CONFIG_SETTER(bool, Bool) #undef TILE_DECLARE_CONFIG_GETTER #undef TILE_DECLARE_CONFIG_SETTER protected: - class ScopedLock { - public: - explicit ScopedLock(const Configuration &config) : config_(config) { - config_.mutex_.Lock(); - } - ~ScopedLock() { config_.mutex_.Unlock(); } + class ScopedLock { + public: + explicit ScopedLock(const Configuration &config) : config_(config) { config_.mutex_.Lock(); } - private: - const Configuration &config_; - }; + ~ScopedLock() { config_.mutex_.Unlock(); } - virtual bool GetRaw(const Slice &key, std::string *value) const = 0; - virtual bool SetRaw(const Slice &key, const Slice &value) = 0; - virtual void RemoveRaw(const Slice &key) = 0; - virtual Keys Enumerate(const Slice &range) const = 0; - void SetRawWithEvent(const Slice &key, const std::string &value); - virtual ~Configuration(); + private: + const Configuration &config_; + }; - friend class std::default_delete; - friend class LayeredConfiguration; + virtual bool GetRaw(const Slice &key, std::string *value) const = 0; + virtual bool SetRaw(const Slice &key, const Slice &value) = 0; + virtual void RemoveRaw(const Slice &key) = 0; + virtual Keys Enumerate(const Slice &range) const = 0; + void SetRawWithEvent(const Slice &key, const std::string &value); + virtual ~Configuration(); + + friend class std::default_delete; + friend class LayeredConfiguration; private: - mutable Mutex mutex_; - bool events_enabled_{false}; + mutable Mutex mutex_; + bool events_enabled_{false}; }; -} // namespace tile +}// namespace tile -#endif // TILE_BASE_CONFIG_CONFIGURATION_H +#endif// TILE_BASE_CONFIG_CONFIGURATION_H diff --git a/tile/base/config/ini_file_configuration.cc b/tile/base/config/ini_file_configuration.cc index 8bb1443..fa66366 100644 --- a/tile/base/config/ini_file_configuration.cc +++ b/tile/base/config/ini_file_configuration.cc @@ -1,143 +1,152 @@ #include "tile/base/config/ini_file_configuration.h" + +#include "tile/base/string.h" #include "tile/base/thread/scoped_lock.h" namespace tile { IniFileConfiguration::IniFileConfiguration() {} + // IniFileConfig::IniFileConfig(std::istream &istr) { load(istr); } // IniFileConfig::IniFileConfig(const std::string &path) { load(path); } IniFileConfiguration::~IniFileConfiguration() {} -bool IniFileConfiguration::load(std::istream &istr) { - if (!istr.good()) { - return false; - } +bool +IniFileConfiguration::load(std::istream &istr) +{ + if (!istr.good()) { return false; } - Configuration::ScopedLock lock(*this); - map_.clear(); - section_key_.clear(); - while (!istr.eof()) { - ParseLine(istr); - } - return true; -} -bool IniFileConfiguration::load(const std::string &path) { - std::ifstream istr(path); - return load(istr); -} -bool IniFileConfiguration::GetRaw(const Slice &key, std::string *value) const { - auto iter = map_.find(key.ToString()); - if (iter != map_.end()) { - *value = iter->second; + Configuration::ScopedLock lock(*this); + map_.clear(); + section_key_.clear(); + while (!istr.eof()) { ParseLine(istr); } return true; - } else { - return false; - } -} -bool IniFileConfiguration::SetRaw(const Slice &key, const Slice &value) { - map_[key] = value; - return true; } -void IniFileConfiguration::RemoveRaw(const Slice &key) { - std::string prefix = key; - if (!prefix.empty()) { - prefix.push_back('.'); - } - IStringMap::iterator it = map_.begin(); - IStringMap::iterator cur; - while (it != map_.end()) { - if (EqualsIgnoreCase(cur->first, key) || - EqualsIgnoreCase(cur->first, prefix)) { - it = map_.erase(cur); +bool +IniFileConfiguration::load(const std::string &path) +{ + std::ifstream istr(path); + return load(istr); +} + +bool +IniFileConfiguration::GetRaw(const Slice &key, std::string *value) const +{ + auto iter = map_.find(key.ToString()); + if (iter != map_.end()) { + *value = iter->second; + return true; } else { - ++it; + return false; } - } } -Configuration::Keys IniFileConfiguration::Enumerate(const Slice &key) const { - Configuration::Keys range; - std::set keys; - std::string prefix = key.ToString(); - if (prefix.empty()) { - prefix.push_back('.'); - } - - std::string::size_type psize = prefix.size(); - for (const auto &p : map_) { - auto &key = p.first; - if (EqualsIgnoreCase(key, prefix, psize)) { - std::string::size_type end = key.find('.', psize); - std::string subkey; - if (end == std::string::npos) { - subkey = key.substr(psize); - } else { - subkey = key.substr(psize, end - psize); - } - - if (keys.find(subkey) == keys.end()) { - keys.insert(subkey); - range.push_back(subkey); - } - } - } - return range; +bool +IniFileConfiguration::SetRaw(const Slice &key, const Slice &value) +{ + map_[key] = value; + return true; } -void IniFileConfiguration::ParseLine(std::istream &istr) { - static const int eof = std::char_traits::eof(); - auto ReadLine = [&](std::string *line) { - line->clear(); - while (true) { - int c = istr.get(); - if (c == eof || c == '\n') { - return c != eof; - } else { - *line += (char)c; - } +void +IniFileConfiguration::RemoveRaw(const Slice &key) +{ + std::string prefix = key; + if (!prefix.empty()) { prefix.push_back('.'); } + IStringMap::iterator it = map_.begin(); + IStringMap::iterator cur; + while (it != map_.end()) { + if (EqualsIgnoreCase(cur->first, key) || EqualsIgnoreCase(cur->first, prefix)) { + it = map_.erase(cur); + } else { + ++it; + } } - }; - - std::string raw_line; - while (ReadLine(&raw_line)) { - if (raw_line.empty()) { - continue; - } - Slice line = TrimLeft(raw_line); - if (line.empty() || line[0] == ';' || line[0] == '#') { - // skip empty line - // skip comment line ; or # - continue; - } - - // parse section - if (line[0] == '[') { - auto pos = line.find(']'); - if (pos == Slice::npos) { - section_key_ = Trim(line.substr(1)); - } else { - section_key_ = Trim(line.substr(1, pos - 1)); - } - } else { - auto strs = Split(line, "=", true, 2); - std::string full_key = section_key_; - if (!full_key.empty()) { - full_key.push_back('.'); - } - full_key.append(Trim(strs[0])); - if (strs.size() > 1) { - map_[full_key] = Trim(strs[1]); - } else { - map_[full_key] = ""; - } - } - } -} -bool IniFileConfiguration::ICompare::operator()(const std::string &s1, - const std::string &s2) const { - auto len = std::min(s1.size(), s2.size()); - return strncmp(s1.c_str(), s2.c_str(), len) < 0; } -} // namespace tile +Configuration::Keys +IniFileConfiguration::Enumerate(const Slice &key) const +{ + Configuration::Keys range; + std::set keys; + std::string prefix = key.ToString(); + if (prefix.empty()) { prefix.push_back('.'); } + + std::string::size_type psize = prefix.size(); + for (const auto &p : map_) { + auto &key = p.first; + if (EqualsIgnoreCase(key, prefix, psize)) { + std::string::size_type end = key.find('.', psize); + std::string subkey; + if (end == std::string::npos) { + subkey = key.substr(psize); + } else { + subkey = key.substr(psize, end - psize); + } + + if (keys.find(subkey) == keys.end()) { + keys.insert(subkey); + range.push_back(subkey); + } + } + } + return range; +} + +void +IniFileConfiguration::ParseLine(std::istream &istr) +{ + static const int eof = std::char_traits::eof(); + auto ReadLine = [&](std::string *line) { + line->clear(); + while (true) { + int c = istr.get(); + if (c == eof || c == '\n') { + return c != eof; + } else { + *line += (char) c; + } + } + }; + + std::string raw_line; + while (ReadLine(&raw_line)) { + if (raw_line.empty()) { continue; } + Slice line = TrimLeft(raw_line); + if (line.empty() || line[0] == ';' || line[0] == '#') { + // skip empty line + // skip comment line ; or # + continue; + } + + // parse section + if (line[0] == '[') { + auto pos = line.find(']'); + if (pos == Slice::npos) { + section_key_ = Trim(line.substr(1)); + } else { + section_key_ = Trim(line.substr(1, pos - 1)); + } + } else { + auto strs = Split(line, "=", true, 2); + std::string full_key = section_key_; + if (!full_key.empty()) { full_key.push_back('.'); } + full_key.append(Trim(strs[0])); + if (strs.size() > 1) { + map_[full_key] = Trim(strs[1]); + } else { + map_[full_key] = ""; + } + } + } +} + +bool +IniFileConfiguration::ICompare::operator()(const std::string &s1, const std::string &s2) const +{ + auto len = std::min(s1.size(), s2.size()); + return strncmp(s1.c_str(), s2.c_str(), len) < 0; +} + +}// namespace tile diff --git a/tile/base/config/ini_file_configuration.h b/tile/base/config/ini_file_configuration.h index 218c1ac..d71b05b 100644 --- a/tile/base/config/ini_file_configuration.h +++ b/tile/base/config/ini_file_configuration.h @@ -9,30 +9,32 @@ namespace tile { class IniFileConfiguration : public Configuration { public: - using Ptr = RefPtr; + using Ptr = RefPtr; - IniFileConfiguration(); - ~IniFileConfiguration() override; - // IniFileConfig(std::istream &istr); - // IniFileConfig(const std::string &path); - bool load(std::istream &istr); - bool load(const std::string &path); + IniFileConfiguration(); + ~IniFileConfiguration() override; + // IniFileConfig(std::istream &istr); + // IniFileConfig(const std::string &path); + bool load(std::istream &istr); + bool load(const std::string &path); protected: - bool GetRaw(const Slice &key, std::string *value) const override; - bool SetRaw(const Slice &key, const Slice &value) override; - void RemoveRaw(const Slice &key) override; - Keys Enumerate(const Slice &range) const override; + bool GetRaw(const Slice &key, std::string *value) const override; + bool SetRaw(const Slice &key, const Slice &value) override; + void RemoveRaw(const Slice &key) override; + Keys Enumerate(const Slice &range) const override; private: - void ParseLine(std::istream &istr); - struct ICompare { - bool operator()(const std::string &s1, const std::string &s2) const; - }; - typedef std::map IStringMap; - IStringMap map_; - std::string section_key_; -}; -} // namespace tile + void ParseLine(std::istream &istr); -#endif // TILE_BASE_CONFIG_INI_FILE_CONFIG_H + struct ICompare { + bool operator()(const std::string &s1, const std::string &s2) const; + }; + + typedef std::map IStringMap; + IStringMap map_; + std::string section_key_; +}; +}// namespace tile + +#endif// TILE_BASE_CONFIG_INI_FILE_CONFIG_H diff --git a/tile/base/config/ini_file_configuration_test.cc b/tile/base/config/ini_file_configuration_test.cc index c8039c5..d789c84 100644 --- a/tile/base/config/ini_file_configuration_test.cc +++ b/tile/base/config/ini_file_configuration_test.cc @@ -17,29 +17,29 @@ a=4 namespace tile { -static_assert( - !detail::HasClassofImpl::value, ""); +static_assert(!detail::HasClassofImpl::value, ""); -TEST(IniFileConfig, LoadFromIStream) { - std::stringstream ss(kIniFileConfig); - Configuration::Ptr config = MakeRefCounted(); - ASSERT_FALSE(config->Has("a")); - ASSERT_FALSE(config->Has("sec1.a")); - ASSERT_FALSE(config->Has("sec3.a")); - if (config.Is()) { - IniFileConfiguration::Ptr ini = config.As(); - ASSERT_TRUE(ini->load(ss)); - } - ASSERT_TRUE(config->Has("a")); - ASSERT_TRUE(config->Has("sec1.a")); - ASSERT_TRUE(config->Has("sec3.a")); - ASSERT_TRUE(config->Has("sec2.kk.a")); +TEST(IniFileConfig, LoadFromIStream) +{ + std::stringstream ss(kIniFileConfig); + Configuration::Ptr config = MakeRefCounted(); + ASSERT_FALSE(config->Has("a")); + ASSERT_FALSE(config->Has("sec1.a")); + ASSERT_FALSE(config->Has("sec3.a")); + if (config.Is()) { + IniFileConfiguration::Ptr ini = config.As(); + ASSERT_TRUE(ini->load(ss)); + } + ASSERT_TRUE(config->Has("a")); + ASSERT_TRUE(config->Has("sec1.a")); + ASSERT_TRUE(config->Has("sec3.a")); + ASSERT_TRUE(config->Has("sec2.kk.a")); - ASSERT_TRUE(config->GetInt("a")); - ASSERT_TRUE(config->GetInt("sec1.a")); - ASSERT_EQ(1, *config->GetInt("a")); - ASSERT_EQ(2, *config->GetInt("sec1.a")); - ASSERT_EQ(3, *config->GetInt("sec3.a")); - ASSERT_EQ(4, *config->GetInt("sec2.kk.a")); + ASSERT_TRUE(config->GetInt("a")); + ASSERT_TRUE(config->GetInt("sec1.a")); + ASSERT_EQ(1, *config->GetInt("a")); + ASSERT_EQ(2, *config->GetInt("sec1.a")); + ASSERT_EQ(3, *config->GetInt("sec3.a")); + ASSERT_EQ(4, *config->GetInt("sec2.kk.a")); } -} // namespace tile +}// namespace tile diff --git a/tile/base/config/json_configuration.cc b/tile/base/config/json_configuration.cc index 65f3e15..64db9d4 100644 --- a/tile/base/config/json_configuration.cc +++ b/tile/base/config/json_configuration.cc @@ -1,141 +1,153 @@ #include "tile/base/config/json_configuration.h" + #include "tile/base/logging.h" +#include "tile/base/string.h" namespace tile { JSONConfiguration::JSONConfiguration() : object_() {} + JSONConfiguration::~JSONConfiguration() {} -bool JSONConfiguration::load(const std::string &path) { - std::ifstream istr(path); - return load(istr); +bool +JSONConfiguration::load(const std::string &path) +{ + std::ifstream istr(path); + return load(istr); } -bool JSONConfiguration::load(std::istream &istr) { - if (!istr.good()) { - return false; - } +bool +JSONConfiguration::load(std::istream &istr) +{ + if (!istr.good()) { return false; } - Configuration::ScopedLock _(*this); - object_.clear(); - Json::Reader reader; - return reader.parse(istr, object_, true); + Configuration::ScopedLock _(*this); + object_.clear(); + Json::Reader reader; + return reader.parse(istr, object_, true); } -void JSONConfiguration::SetInt(const Slice &key, int value) { - Configuration::ScopedLock _(*this); - SetValue(key, value); +void +JSONConfiguration::SetInt(const Slice &key, int value) +{ + Configuration::ScopedLock _(*this); + SetValue(key, value); } -void JSONConfiguration::SetBool(const Slice &key, bool value) { - Configuration::ScopedLock _(*this); - SetValue(key, value); +void +JSONConfiguration::SetBool(const Slice &key, bool value) +{ + Configuration::ScopedLock _(*this); + SetValue(key, value); } -void JSONConfiguration::SetDouble(const Slice &key, double value) { - Configuration::ScopedLock _(*this); - SetValue(key, value); +void +JSONConfiguration::SetDouble(const Slice &key, double value) +{ + Configuration::ScopedLock _(*this); + SetValue(key, value); } -void JSONConfiguration::SetString(const Slice &key, const std::string &value) { - Configuration::ScopedLock _(*this); - SetValue(key, value); +void +JSONConfiguration::SetString(const Slice &key, const std::string &value) +{ + Configuration::ScopedLock _(*this); + SetValue(key, value); } -void JSONConfiguration::RemoveRaw(const Slice &key) { - Json::Value *root; - Slice last_part; - if (!FindStart(key, &last_part, &root)) { - return; - } - root->removeMember(last_part); -} -std::string JSONConfiguration::Dump() const { - Configuration::ScopedLock _(*this); - return object_.toStyledString(); +void +JSONConfiguration::RemoveRaw(const Slice &key) +{ + Json::Value *root; + Slice last_part; + if (!FindStart(key, &last_part, &root)) { return; } + root->removeMember(last_part); } -bool JSONConfiguration::GetRaw(const Slice &key, std::string *value) const { - auto keys = Split(key, '.'); - auto root = object_; - for (std::size_t i = 0; i < keys.size(); ++i) { - const auto &cur_key = keys[i]; - if (cur_key.empty()) { - TILE_LOG_ERROR("Invalid key: {}", key); - return false; - } - if (!root.isMember(cur_key)) { - return false; - } - root = root[cur_key]; - } - - if (root.isConvertibleTo(Json::stringValue)) { - *value = root.asString(); - } else { - *value = root.toStyledString(); - } - return true; +std::string +JSONConfiguration::Dump() const +{ + Configuration::ScopedLock _(*this); + return object_.toStyledString(); } -bool JSONConfiguration::SetRaw(const Slice &key, const Slice &value) { - return SetValue(key, value.ToString()); -} - -Configuration::Keys JSONConfiguration::Enumerate(const Slice &range) const { - Configuration::Keys key_set; - std::string prefix = range; - if (!prefix.empty()) { - prefix += "."; - } - - auto keys = Split(range, '.'); - auto root = object_; - for (std::size_t i = 0; i < keys.size(); ++i) { - const auto &cur_key = keys[i]; - if (cur_key.empty()) { - TILE_LOG_ERROR("Invalid range: {}", range); - return key_set; - } - if (!root.isMember(cur_key)) { - return key_set; - } - root = root[cur_key]; - } - - for (const auto &key : root.getMemberNames()) { - key_set.push_back(prefix + key); - } - return key_set; -} - -bool JSONConfiguration::FindStart(const Slice &key, Slice *last_part, - Json::Value **parent_obj) { - auto keys = Split(key, '.'); - if (keys.empty()) { - return false; - } - - Json::Value *root = &object_; - for (std::size_t i = 0; i < keys.size() - 1; ++i) { - const auto &cur_key = keys[i]; - if (cur_key.empty()) { - TILE_LOG_ERROR("Invalid key: {}", key); - return false; +bool +JSONConfiguration::GetRaw(const Slice &key, std::string *value) const +{ + auto keys = Split(key, '.'); + auto root = object_; + for (std::size_t i = 0; i < keys.size(); ++i) { + const auto &cur_key = keys[i]; + if (cur_key.empty()) { + TILE_LOG_ERROR("Invalid key: {}", key); + return false; + } + if (!root.isMember(cur_key)) { return false; } + root = root[cur_key]; } - if (!root->isMember(cur_key)) { - (*root)[cur_key] = Json::Value(Json::objectValue); - } else if (!(*root)[cur_key].isObject()) { - TILE_LOG_ERROR("only leaf nodes can be set: key: {}, cur_key(idx={}): {}", - key, i, cur_key); - return false; + if (root.isConvertibleTo(Json::stringValue)) { + *value = root.asString(); + } else { + *value = root.toStyledString(); } - root = &(*root)[cur_key]; - } - - *last_part = keys.back(); - *parent_obj = root; - return true; + return true; } -} // namespace tile +bool +JSONConfiguration::SetRaw(const Slice &key, const Slice &value) +{ + return SetValue(key, value.ToString()); +} + +Configuration::Keys +JSONConfiguration::Enumerate(const Slice &range) const +{ + Configuration::Keys key_set; + std::string prefix = range; + if (!prefix.empty()) { prefix += "."; } + + auto keys = Split(range, '.'); + auto root = object_; + for (std::size_t i = 0; i < keys.size(); ++i) { + const auto &cur_key = keys[i]; + if (cur_key.empty()) { + TILE_LOG_ERROR("Invalid range: {}", range); + return key_set; + } + if (!root.isMember(cur_key)) { return key_set; } + root = root[cur_key]; + } + + for (const auto &key : root.getMemberNames()) { key_set.push_back(prefix + key); } + return key_set; +} + +bool +JSONConfiguration::FindStart(const Slice &key, Slice *last_part, Json::Value **parent_obj) +{ + auto keys = Split(key, '.'); + if (keys.empty()) { return false; } + + Json::Value *root = &object_; + for (std::size_t i = 0; i < keys.size() - 1; ++i) { + const auto &cur_key = keys[i]; + if (cur_key.empty()) { + TILE_LOG_ERROR("Invalid key: {}", key); + return false; + } + + if (!root->isMember(cur_key)) { + (*root)[cur_key] = Json::Value(Json::objectValue); + } else if (!(*root)[cur_key].isObject()) { + TILE_LOG_ERROR("only leaf nodes can be set: key: {}, cur_key(idx={}): {}", key, i, cur_key); + return false; + } + root = &(*root)[cur_key]; + } + + *last_part = keys.back(); + *parent_obj = root; + return true; +} + +}// namespace tile diff --git a/tile/base/config/json_configuration.h b/tile/base/config/json_configuration.h index be45c3a..f9c774e 100644 --- a/tile/base/config/json_configuration.h +++ b/tile/base/config/json_configuration.h @@ -9,41 +9,42 @@ namespace tile { class JSONConfiguration : public Configuration { public: - using Ptr = RefPtr; - JSONConfiguration(); - ~JSONConfiguration() override; - bool load(const std::string &path); - bool load(std::istream &istr); + using Ptr = RefPtr; + JSONConfiguration(); + ~JSONConfiguration() override; + bool load(const std::string &path); + bool load(std::istream &istr); - void SetInt(const Slice &key, int value) override; - void SetBool(const Slice &key, bool value) override; - void SetDouble(const Slice &key, double value) override; - void SetString(const Slice &key, const std::string &value) override; - void RemoveRaw(const Slice &key) override; + void SetInt(const Slice &key, int value) override; + void SetBool(const Slice &key, bool value) override; + void SetDouble(const Slice &key, double value) override; + void SetString(const Slice &key, const std::string &value) override; + void RemoveRaw(const Slice &key) override; - std::string Dump() const; + std::string Dump() const; protected: - bool GetRaw(const Slice &key, std::string *value) const override; - bool SetRaw(const Slice &key, const Slice &value) override; - Keys Enumerate(const Slice &range) const override; + bool GetRaw(const Slice &key, std::string *value) const override; + bool SetRaw(const Slice &key, const Slice &value) override; + Keys Enumerate(const Slice &range) const override; private: - bool FindStart(const Slice &key, Slice *last_prt, Json::Value **parent_obj); - template bool SetValue(const Slice &key, T value); - Json::Value object_; + bool FindStart(const Slice &key, Slice *last_prt, Json::Value **parent_obj); + template + bool SetValue(const Slice &key, T value); + Json::Value object_; }; -template -bool JSONConfiguration::SetValue(const Slice &key, T value) { - Slice last_part; - Json::Value *root; - if (!FindStart(key, &last_part, &root)) { - return false; - } - (*root)[last_part] = Json::Value(value); - return true; +template +bool +JSONConfiguration::SetValue(const Slice &key, T value) +{ + Slice last_part; + Json::Value *root; + if (!FindStart(key, &last_part, &root)) { return false; } + (*root)[last_part] = Json::Value(value); + return true; } -} // namespace tile +}// namespace tile -#endif // TILE_BASE_CONFIG_JSON_CONFIGURATION_H +#endif// TILE_BASE_CONFIG_JSON_CONFIGURATION_H diff --git a/tile/base/config/json_configuration_test.cc b/tile/base/config/json_configuration_test.cc index e213681..eee5327 100644 --- a/tile/base/config/json_configuration_test.cc +++ b/tile/base/config/json_configuration_test.cc @@ -18,81 +18,87 @@ const char *kJsonConfig = R"( )"; } -TEST(JSONConfiguration, Load) { - JSONConfiguration config; - std::istringstream istr(kJsonConfig); - ASSERT_TRUE(config.load(istr)); -} -TEST(JSONConfiguration, Has) { - JSONConfiguration config; - std::istringstream istr(kJsonConfig); - ASSERT_TRUE(config.load(istr)); - - ASSERT_TRUE(config.Has("key1")); - ASSERT_TRUE(config.Has("key2")); - ASSERT_TRUE(config.Has("key3")); - ASSERT_TRUE(config.Has("key4")); - ASSERT_TRUE(config.Has("key5")); - ASSERT_TRUE(config.Has("key5.key51")); - ASSERT_TRUE(config.Has("key5.key52")); +TEST(JSONConfiguration, Load) +{ + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); } -TEST(JSONConfiguration, SampleSet) { - JSONConfiguration config; - std::istringstream istr(kJsonConfig); - ASSERT_TRUE(config.load(istr)); - ASSERT_TRUE(config.GetInt32("key2")); - ASSERT_EQ(*config.GetInt32("key2"), 2); +TEST(JSONConfiguration, Has) +{ + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); - config.SetInt("key2", 20); - ASSERT_TRUE(config.GetInt32("key2")); - ASSERT_EQ(20, *config.GetInt32("key2")) << config.Dump(); - - config.SetDouble("key3", 30.0); - ASSERT_TRUE(config.GetDouble("key3")); - ASSERT_NEAR(30.0, *config.GetDouble("key3"), 0.0001) << config.Dump(); - - config.SetBool("key4", false); - ASSERT_TRUE(config.GetBool("key4")); - ASSERT_FALSE(*config.GetBool("key4")) << config.Dump(); + ASSERT_TRUE(config.Has("key1")); + ASSERT_TRUE(config.Has("key2")); + ASSERT_TRUE(config.Has("key3")); + ASSERT_TRUE(config.Has("key4")); + ASSERT_TRUE(config.Has("key5")); + ASSERT_TRUE(config.Has("key5.key51")); + ASSERT_TRUE(config.Has("key5.key52")); } -TEST(JSONConfiguration, LayeredSet) { - JSONConfiguration config; - std::istringstream istr(kJsonConfig); - ASSERT_TRUE(config.load(istr)); +TEST(JSONConfiguration, SampleSet) +{ + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + ASSERT_TRUE(config.GetInt32("key2")); + ASSERT_EQ(*config.GetInt32("key2"), 2); - // ASSERT_TRUE(config.GetInt32("key5.key52")); - config.SetInt("key5.key52", 520); - ASSERT_TRUE(config.GetInt32("key5.key52")) << config.Dump(); - ASSERT_EQ(520, *config.GetInt32("key5.key52")) << config.Dump(); + config.SetInt("key2", 20); + ASSERT_TRUE(config.GetInt32("key2")); + ASSERT_EQ(20, *config.GetInt32("key2")) << config.Dump(); - // override by other type - config.SetBool("key5.key52", false); - ASSERT_TRUE(config.GetBool("key5.key52")) << config.Dump(); - ASSERT_FALSE(*config.GetBool("key5.key52")) << config.Dump(); + config.SetDouble("key3", 30.0); + ASSERT_TRUE(config.GetDouble("key3")); + ASSERT_NEAR(30.0, *config.GetDouble("key3"), 0.0001) << config.Dump(); + + config.SetBool("key4", false); + ASSERT_TRUE(config.GetBool("key4")); + ASSERT_FALSE(*config.GetBool("key4")) << config.Dump(); } -TEST(json_configuration, Enumerate) { - JSONConfiguration config; - std::istringstream istr(kJsonConfig); - ASSERT_TRUE(config.load(istr)); - auto keys = config.keys(""); - ASSERT_EQ(5, keys.size()); - ASSERT_EQ("key1", keys[0]); - ASSERT_EQ("key2", keys[1]); - ASSERT_EQ("key3", keys[2]); - ASSERT_EQ("key4", keys[3]); - ASSERT_EQ("key5", keys[4]); +TEST(JSONConfiguration, LayeredSet) +{ + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); - keys = config.keys("key5"); - ASSERT_EQ(2, keys.size()); - ASSERT_EQ("key5.key51", keys[0]); - ASSERT_EQ("key5.key52", keys[1]); + // ASSERT_TRUE(config.GetInt32("key5.key52")); + config.SetInt("key5.key52", 520); + ASSERT_TRUE(config.GetInt32("key5.key52")) << config.Dump(); + ASSERT_EQ(520, *config.GetInt32("key5.key52")) << config.Dump(); - config.Remove("key5.key51"); - keys = config.keys("key5"); - ASSERT_EQ("key5.key52", keys[0]); + // override by other type + config.SetBool("key5.key52", false); + ASSERT_TRUE(config.GetBool("key5.key52")) << config.Dump(); + ASSERT_FALSE(*config.GetBool("key5.key52")) << config.Dump(); } -} // namespace tile +TEST(json_configuration, Enumerate) +{ + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + auto keys = config.keys(""); + ASSERT_EQ(5, keys.size()); + ASSERT_EQ("key1", keys[0]); + ASSERT_EQ("key2", keys[1]); + ASSERT_EQ("key3", keys[2]); + ASSERT_EQ("key4", keys[3]); + ASSERT_EQ("key5", keys[4]); + + keys = config.keys("key5"); + ASSERT_EQ(2, keys.size()); + ASSERT_EQ("key5.key51", keys[0]); + ASSERT_EQ("key5.key52", keys[1]); + + config.Remove("key5.key51"); + keys = config.keys("key5"); + ASSERT_EQ("key5.key52", keys[0]); +} + +}// namespace tile diff --git a/tile/base/config/layered_configuration.cc b/tile/base/config/layered_configuration.cc index ea62c5e..d07e380 100644 --- a/tile/base/config/layered_configuration.cc +++ b/tile/base/config/layered_configuration.cc @@ -3,129 +3,147 @@ namespace tile { LayeredConfiguration::LayeredConfiguration() {} + LayeredConfiguration::~LayeredConfiguration() {} -void LayeredConfiguration::Add(Configuration::Ptr cfg) { - Add(cfg, highest(), false); +void +LayeredConfiguration::Add(Configuration::Ptr cfg) +{ + Add(cfg, highest(), false); } -void LayeredConfiguration::Add(Configuration::Ptr cfg, int priority) { - Add(cfg, priority, false); +void +LayeredConfiguration::Add(Configuration::Ptr cfg, int priority) +{ + Add(cfg, priority, false); } -void LayeredConfiguration::Add(Configuration::Ptr cfg, - const std::string &label) { - Add(cfg, label, highest(), false); +void +LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label) +{ + Add(cfg, label, highest(), false); } -void LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, - int priority) { - Add(cfg, label, priority, false); +void +LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, int priority) +{ + Add(cfg, label, priority, false); } -void LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, - bool writeable) { - Add(cfg, label, highest(), writeable); +void +LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, bool writeable) +{ + Add(cfg, label, highest(), writeable); } -void LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, - int priority, bool writeable) { - Configuration::ScopedLock lock(*this); - ConfigItem item; - item.cfg = cfg; - item.priority = priority; - item.writeable = writeable; - item.label = label; - auto it = configs_.begin(); - while (it != configs_.end() && it->priority < priority) { - ++it; - } - configs_.insert(it, item); +void +LayeredConfiguration::Add(Configuration::Ptr cfg, const std::string &label, int priority, bool writeable) +{ + Configuration::ScopedLock lock(*this); + ConfigItem item; + item.cfg = cfg; + item.priority = priority; + item.writeable = writeable; + item.label = label; + auto it = configs_.begin(); + while (it != configs_.end() && it->priority < priority) { ++it; } + configs_.insert(it, item); } -void LayeredConfiguration::Add(Configuration::Ptr cfg, int priority, - bool writeable) { - Add(cfg, std::string(), priority, writeable); -} -void LayeredConfiguration::AddWriteable(Configuration::Ptr cfg, int priority) { - Add(cfg, priority, true); +void +LayeredConfiguration::Add(Configuration::Ptr cfg, int priority, bool writeable) +{ + Add(cfg, std::string(), priority, writeable); } -Configuration::Ptr LayeredConfiguration::Find(const Slice &label) const { - Configuration::ScopedLock lock(*this); +void +LayeredConfiguration::AddWriteable(Configuration::Ptr cfg, int priority) +{ + Add(cfg, priority, true); +} - for (const auto &conf : configs_) { - if (conf.label == label) { - return conf.cfg; +Configuration::Ptr +LayeredConfiguration::Find(const Slice &label) const +{ + Configuration::ScopedLock lock(*this); + + for (const auto &conf : configs_) { + if (conf.label == label) { return conf.cfg; } } - } - return 0; + return 0; } -void LayeredConfiguration::RemoveConfig(Configuration::Ptr cfg) { - Configuration::ScopedLock lock(*this); - for (auto it = configs_.begin(); it != configs_.end();) { - if (it->cfg == cfg) { - it = configs_.erase(it); +void +LayeredConfiguration::RemoveConfig(Configuration::Ptr cfg) +{ + Configuration::ScopedLock lock(*this); + for (auto it = configs_.begin(); it != configs_.end();) { + if (it->cfg == cfg) { + it = configs_.erase(it); + } else { + ++it; + } + } +} + +bool +LayeredConfiguration::GetRaw(const Slice &key, std::string *value) const +{ + for (const auto &conf : configs_) { + if (conf.cfg->GetRaw(key, value)) { return true; } + } + return false; +} + +bool +LayeredConfiguration::SetRaw(const Slice &key, const Slice &value) +{ + for (const auto &conf : configs_) { + if (conf.writeable && conf.cfg->SetRaw(key, value)) { return true; } + } + return false; +} + +Configuration::Keys +LayeredConfiguration::Enumerate(const Slice &key) const +{ + Configuration::Keys keys; + std::set key_set; + for (const auto &conf : configs_) { + auto conf_keys = conf.cfg->Enumerate(key); + for (const auto &k : conf_keys) { + if (key_set.insert(k).second) { keys.push_back(k); } + } + } + return keys; +} + +void +LayeredConfiguration::RemoveRaw(const std::string &key) +{ + for (auto &conf : configs_) { + if (conf.writeable) { conf.cfg->RemoveRaw(key); } + } +} + +int +LayeredConfiguration::lowest() const +{ + if (configs_.empty()) { + return 0; } else { - ++it; + return configs_.front().priority - 1; } - } } -bool LayeredConfiguration::GetRaw(const Slice &key, std::string *value) const { - for (const auto &conf : configs_) { - if (conf.cfg->GetRaw(key, value)) { - return true; +int +LayeredConfiguration::highest() const +{ + if (configs_.empty()) { + return 0; + } else { + return configs_.back().priority + 1; } - } - return false; } -bool LayeredConfiguration::SetRaw(const Slice &key, const Slice &value) { - for (const auto &conf : configs_) { - if (conf.writeable && conf.cfg->SetRaw(key, value)) { - return true; - } - } - return false; -} - -Configuration::Keys LayeredConfiguration::Enumerate(const Slice &key) const { - Configuration::Keys keys; - std::set key_set; - for (const auto &conf : configs_) { - auto conf_keys = conf.cfg->Enumerate(key); - for (const auto &k : conf_keys) { - if (key_set.insert(k).second) { - keys.push_back(k); - } - } - } - return keys; -} - -void LayeredConfiguration::RemoveRaw(const std::string &key) { - for (auto &conf : configs_) { - if (conf.writeable) { - conf.cfg->RemoveRaw(key); - } - } -} - -int LayeredConfiguration::lowest() const { - if (configs_.empty()) { - return 0; - } else { - return configs_.front().priority - 1; - } -} -int LayeredConfiguration::highest() const { - if (configs_.empty()) { - return 0; - } else { - return configs_.back().priority + 1; - } -} - -} // namespace tile +}// namespace tile diff --git a/tile/base/config/layered_configuration.h b/tile/base/config/layered_configuration.h index aa8f9de..aba8f4a 100644 --- a/tile/base/config/layered_configuration.h +++ b/tile/base/config/layered_configuration.h @@ -9,47 +9,46 @@ namespace tile { class LayeredConfiguration : public Configuration { public: - using Ptr = RefPtr; - LayeredConfiguration(); - LayeredConfiguration(const LayeredConfiguration &) = delete; - LayeredConfiguration &operator=(const LayeredConfiguration &) = delete; + using Ptr = RefPtr; + LayeredConfiguration(); + LayeredConfiguration(const LayeredConfiguration &) = delete; + LayeredConfiguration &operator=(const LayeredConfiguration &) = delete; - void Add(Configuration::Ptr cfg); - void Add(Configuration::Ptr cfg, int priority); - void Add(Configuration::Ptr cfg, const std::string &label); - void Add(Configuration::Ptr cfg, const std::string &label, int priority); - void Add(Configuration::Ptr cfg, const std::string &label, bool writeable); - void Add(Configuration::Ptr cfg, const std::string &label, int priority, - bool writeable); - void Add(Configuration::Ptr cfg, int priority, bool writeable); - void AddWriteable(Configuration::Ptr cfg, int priority); - Configuration::Ptr Find(const Slice &label) const; - void RemoveConfig(Configuration::Ptr cfg); + void Add(Configuration::Ptr cfg); + void Add(Configuration::Ptr cfg, int priority); + void Add(Configuration::Ptr cfg, const std::string &label); + void Add(Configuration::Ptr cfg, const std::string &label, int priority); + void Add(Configuration::Ptr cfg, const std::string &label, bool writeable); + void Add(Configuration::Ptr cfg, const std::string &label, int priority, bool writeable); + void Add(Configuration::Ptr cfg, int priority, bool writeable); + void AddWriteable(Configuration::Ptr cfg, int priority); + Configuration::Ptr Find(const Slice &label) const; + void RemoveConfig(Configuration::Ptr cfg); protected: - struct ConfigItem { - Configuration::Ptr cfg; - // ... > -2 > -1 > 0 > 1 > 2 > 3 > 4 ... - int priority; - // can remove or set new? - bool writeable; - std::string label; - }; + struct ConfigItem { + Configuration::Ptr cfg; + // ... > -2 > -1 > 0 > 1 > 2 > 3 > 4 ... + int priority; + // can remove or set new? + bool writeable; + std::string label; + }; - bool GetRaw(const Slice &key, std::string *value) const override; - bool SetRaw(const Slice &key, const Slice &value) override; - Configuration::Keys Enumerate(const Slice &key) const override; - void RemoveRaw(const std::string &key); + bool GetRaw(const Slice &key, std::string *value) const override; + bool SetRaw(const Slice &key, const Slice &value) override; + Configuration::Keys Enumerate(const Slice &key) const override; + void RemoveRaw(const std::string &key); - int lowest() const; - int highest() const; + int lowest() const; + int highest() const; - ~LayeredConfiguration(); + ~LayeredConfiguration(); private: - using ConfigList = std::list; - ConfigList configs_; + using ConfigList = std::list; + ConfigList configs_; }; -} // namespace tile +}// namespace tile -#endif // TILE_BASE_CONFIG_LAYERED_CONFIGURATION_H +#endif// TILE_BASE_CONFIG_LAYERED_CONFIGURATION_H diff --git a/tile/base/configuration.h b/tile/base/configuration.h index 0a980a9..50cf5f3 100644 --- a/tile/base/configuration.h +++ b/tile/base/configuration.h @@ -8,4 +8,4 @@ #include "tile/base/config/ini_file_configuration.h" #include "tile/base/config/layered_configuration.h" -#endif // TILE_BASE_CONFIGURATION_H +#endif// TILE_BASE_CONFIGURATION_H diff --git a/tile/base/data.h b/tile/base/data.h index 77a321d..8f17b7d 100644 --- a/tile/base/data.h +++ b/tile/base/data.h @@ -4,4 +4,4 @@ #pragma once #include "tile/base/data/json.h" -#endif // TILE_BASE_DATA_H +#endif// TILE_BASE_DATA_H diff --git a/tile/base/data/json.h b/tile/base/data/json.h index 21dec79..3c69b7e 100644 --- a/tile/base/data/json.h +++ b/tile/base/data/json.h @@ -11,28 +11,34 @@ namespace tile { -template -auto ToJson(const T &value) - -> enable_if_t::value, Json::Value> { - return static_cast(value); +template +auto +ToJson(const T &value) -> enable_if_t::value, Json::Value> +{ + return static_cast(value); } -template -auto ToJson(const T &value) - -> enable_if_t::value, Json::Value> { - return static_cast(value); -} -template -auto ToJson(const T &value) - -> enable_if_t::value && !std::is_unsigned::value, - Json::Value> { - return Format("{}", value); +template +auto +ToJson(const T &value) -> enable_if_t::value, Json::Value> +{ + return static_cast(value); } -template Json::Value ToJson(const std::atomic &v) { - return ToJson(v.load(std::memory_order_relaxed)); +template +auto +ToJson(const T &value) -> enable_if_t::value && !std::is_unsigned::value, Json::Value> +{ + return Format("{}", value); } -} // namespace tile +template +Json::Value +ToJson(const std::atomic &v) +{ + return ToJson(v.load(std::memory_order_relaxed)); +} -#endif // TILE_BASE_DATA_JSON_H +}// namespace tile + +#endif// TILE_BASE_DATA_JSON_H diff --git a/tile/base/deferred.h b/tile/base/deferred.h index cf5a054..ce0297e 100644 --- a/tile/base/deferred.h +++ b/tile/base/deferred.h @@ -9,56 +9,57 @@ namespace tile { class ScopedDeferred { public: - template - explicit ScopedDeferred(F &&f) : action_(std::move(f)) {} + template + explicit ScopedDeferred(F &&f) : action_(std::move(f)) + {} - ~ScopedDeferred() { action_(); } - ScopedDeferred(const ScopedDeferred &) = delete; - ScopedDeferred &operator=(const ScopedDeferred &) = delete; + ~ScopedDeferred() { action_(); } + + ScopedDeferred(const ScopedDeferred &) = delete; + ScopedDeferred &operator=(const ScopedDeferred &) = delete; private: - std::function action_; + std::function action_; }; class Deferred { public: - Deferred() = default; - template - explicit Deferred(F &&f) : action_(std::forward(f)) {} + Deferred() = default; - Deferred(Deferred &&other) noexcept : action_(std::move(other.action_)) { - other.action_ = nullptr; - } - Deferred &operator=(Deferred &&other) noexcept { - if (&other == this) { - return *this; + template + explicit Deferred(F &&f) : action_(std::forward(f)) + {} + + Deferred(Deferred &&other) noexcept : action_(std::move(other.action_)) { other.action_ = nullptr; } + + Deferred &operator=(Deferred &&other) noexcept + { + if (&other == this) { return *this; } + + Fire(); + action_ = std::move(other.action_); + other.action_ = nullptr; + return *this; } - Fire(); - action_ = std::move(other.action_); - other.action_ = nullptr; - return *this; - } - ~Deferred() { - if (action_) { - action_(); + ~Deferred() + { + if (action_) { action_(); } } - } - explicit operator bool() const noexcept { return !!action_; } + explicit operator bool() const noexcept { return !!action_; } - void Fire() noexcept { - if (auto op = std::move(action_)) { - op(); + void Fire() noexcept + { + if (auto op = std::move(action_)) { op(); } } - } - void Dimiss() noexcept { action_ = nullptr; } + void Dimiss() noexcept { action_ = nullptr; } private: - std::function action_; + std::function action_; }; -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_DEFERED_H +#endif// _TILE_BASE_DEFERED_H diff --git a/tile/base/deferred_test.cc b/tile/base/deferred_test.cc index 373768a..5a73ce5 100644 --- a/tile/base/deferred_test.cc +++ b/tile/base/deferred_test.cc @@ -2,49 +2,51 @@ #include "gtest/gtest.h" namespace tile { -TEST(ScopedDefered, All) { - bool f = false; - { - ScopedDeferred scoped_defered([&] { f = true; }); - ASSERT_FALSE(f); - } - ASSERT_TRUE(f); +TEST(ScopedDefered, All) +{ + bool f = false; + { + ScopedDeferred scoped_defered([&] { f = true; }); + ASSERT_FALSE(f); + } + ASSERT_TRUE(f); } -TEST(Defered, All) { - bool f1 = false; - bool f2 = false; - { - Deferred defer([&] { f1 = true; }); - ASSERT_FALSE(f1); - Deferred defer2([&] { f2 = true; }); - defer2.Dimiss(); +TEST(Defered, All) +{ + bool f1 = false; + bool f2 = false; + { + Deferred defer([&] { f1 = true; }); + ASSERT_FALSE(f1); + Deferred defer2([&] { f2 = true; }); + defer2.Dimiss(); + ASSERT_FALSE(f2); + } + ASSERT_TRUE(f1); ASSERT_FALSE(f2); - } - ASSERT_TRUE(f1); - ASSERT_FALSE(f2); - bool f3 = false; - Deferred defer3([&] { f3 = true; }); - ASSERT_FALSE(f3); - defer3.Fire(); - ASSERT_TRUE(f3); + bool f3 = false; + Deferred defer3([&] { f3 = true; }); + ASSERT_FALSE(f3); + defer3.Fire(); + ASSERT_TRUE(f3); - bool f4 = false; - Deferred defer5; - { - Deferred defer4([&] { f4 = true; }); + bool f4 = false; + Deferred defer5; + { + Deferred defer4([&] { f4 = true; }); + ASSERT_FALSE(f4); + defer5 = std::move(defer4); + } ASSERT_FALSE(f4); - defer5 = std::move(defer4); - } - ASSERT_FALSE(f4); - auto defer6 = std::move(defer5); - defer5.Fire(); - ASSERT_FALSE(defer5); - defer6.Fire(); - ASSERT_TRUE(f4); + auto defer6 = std::move(defer5); + defer5.Fire(); + ASSERT_FALSE(defer5); + defer6.Fire(); + ASSERT_TRUE(f4); - Deferred().Fire(); - Deferred().Dimiss(); + Deferred().Fire(); + Deferred().Dimiss(); } -} // namespace tile +}// namespace tile diff --git a/tile/base/demangle.cc b/tile/base/demangle.cc index 7d68f68..97fbbf9 100644 --- a/tile/base/demangle.cc +++ b/tile/base/demangle.cc @@ -10,21 +10,21 @@ namespace tile { -std::string Demangle(const char *s) { +std::string +Demangle(const char *s) +{ #ifdef _MSC_VER - return s; -#elif defined(__GNUC__) || defined(__clang__) - int status; - char *demangled = abi::__cxa_demangle(s, nullptr, nullptr, &status); - ScopedDeferred _([&] { free(demangled); }); - if (!demangled) { return s; - } - return demangled; +#elif defined(__GNUC__) || defined(__clang__) + int status; + char *demangled = abi::__cxa_demangle(s, nullptr, nullptr, &status); + ScopedDeferred _([&] { free(demangled); }); + if (!demangled) { return s; } + return demangled; #else #error "Demangle not supported on current compiler." #endif } -} // namespace tile +}// namespace tile diff --git a/tile/base/demangle.h b/tile/base/demangle.h index 8df72b8..00109ce 100644 --- a/tile/base/demangle.h +++ b/tile/base/demangle.h @@ -11,8 +11,11 @@ namespace tile { std::string Demangle(const char *s); -template std::string GetTypeName() { - return Demangle(typeid(T).name()); +template +std::string +GetTypeName() +{ + return Demangle(typeid(T).name()); } #if __GNUC__ >= 12 @@ -20,14 +23,17 @@ template std::string GetTypeName() { #pragma GCC diagnostic ignored "-Wnonnull-compare" #endif -template std::string GetTypeName(T &&o) { - return Demangle(typeid(std::forward(o)).name()); +template +std::string +GetTypeName(T &&o) +{ + return Demangle(typeid(std::forward(o)).name()); } #if __GNUC__ >= 12 #pragma GCC diagnostic pop #endif -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_DEMANGLE_H +#endif// _TILE_BASE_DEMANGLE_H diff --git a/tile/base/demangle_test.cc b/tile/base/demangle_test.cc index 68ae2b0..81970de 100644 --- a/tile/base/demangle_test.cc +++ b/tile/base/demangle_test.cc @@ -3,16 +3,16 @@ namespace tile { struct C { - struct D { - struct E {}; - }; + struct D { + struct E {}; + }; }; -TEST(Demangle, All) { - ASSERT_EQ("tile::C::D::E", GetTypeName()); - ASSERT_NE(GetTypeName(), typeid(C::D::E).name()); - ASSERT_EQ("invalid function name !@#$", - Demangle("invalid function name !@#$")); +TEST(Demangle, All) +{ + ASSERT_EQ("tile::C::D::E", GetTypeName()); + ASSERT_NE(GetTypeName(), typeid(C::D::E).name()); + ASSERT_EQ("invalid function name !@#$", Demangle("invalid function name !@#$")); } -} // namespace tile +}// namespace tile diff --git a/tile/base/dependency_registry.h b/tile/base/dependency_registry.h index ac23ae6..14a3db8 100644 --- a/tile/base/dependency_registry.h +++ b/tile/base/dependency_registry.h @@ -21,186 +21,174 @@ #include // class dependency -#define TILE_DECLARE_CLASS_DEPENDENCY_REGISTRY(Registry, Interface, ...) \ - extern ::tile::detail::dependency_registry::ClassRegistry< \ - struct Registry, Interface, ##__VA_ARGS__> &Registry +#define TILE_DECLARE_CLASS_DEPENDENCY_REGISTRY(Registry, Interface, ...) \ + extern ::tile::detail::dependency_registry::ClassRegistry &Registry -#define TILE_DEFINE_CLASS_DEPENDENCY_REGISTRY(Registry, Interface, ...) \ - ::tile::detail::dependency_registry::ClassRegistry< \ - struct Registry, Interface, ##__VA_ARGS__> &Registry = \ - **::tile::internal::LazyInit<::tile::NeverDestroyed< \ - ::tile::detail::dependency_registry::ClassRegistry< \ - struct Registry, Interface, ##__VA_ARGS__>>>() +#define TILE_DEFINE_CLASS_DEPENDENCY_REGISTRY(Registry, Interface, ...) \ + ::tile::detail::dependency_registry::ClassRegistry &Registry = \ + **::tile::internal::LazyInit<::tile::NeverDestroyed< \ + ::tile::detail::dependency_registry::ClassRegistry>>() -#define TILE_REGISTER_CLASS_DEPENDENCY(Registry, ImplementationName, \ - ImplementationClassName, ...) \ - TILE_REGISTER_CLASS_DEPENDENCY_FACTORY( \ - Registry, ImplementationName, \ - TILE_REGISTER_CLASS_DEPENDENCY_FUNCTION_AUX_INVOKE( \ - ImplementationClassName, ##__VA_ARGS__)) +#define TILE_REGISTER_CLASS_DEPENDENCY(Registry, ImplementationName, ImplementationClassName, ...) \ + TILE_REGISTER_CLASS_DEPENDENCY_FACTORY( \ + Registry, ImplementationName, \ + TILE_REGISTER_CLASS_DEPENDENCY_FUNCTION_AUX_INVOKE(ImplementationClassName, ##__VA_ARGS__)) -#define TILE_REGISTER_CLASS_DEPENDENCY_FACTORY(Registry, Name, Factory) \ - __attribute__((constructor)) static void TILE_INTERNAL_PP_CAT( \ - tile_reserved_registry_dependency_class_register_, __COUNTER__)() { \ - auto registry = ::tile::internal::LazyInit<::tile::NeverDestroyed< \ - typename std::decay::type>>() \ - ->Get(); \ - ::tile::detail::dependency_registry::AddToRegistry(registry, Name, \ - Factory); \ - } +#define TILE_REGISTER_CLASS_DEPENDENCY_FACTORY(Registry, Name, Factory) \ + __attribute__((constructor)) static void TILE_INTERNAL_PP_CAT( \ + tile_reserved_registry_dependency_class_register_, __COUNTER__)() \ + { \ + auto registry = \ + ::tile::internal::LazyInit<::tile::NeverDestroyed::type>>() \ + ->Get(); \ + ::tile::detail::dependency_registry::AddToRegistry(registry, Name, Factory); \ + } // object dependency -#define TILE_DECLARE_OBJECT_DEPENDENCY_REGISTRY(Registry, Interface) \ - extern ::tile::detail::dependency_registry::ObjectRegistry< \ - struct Registry, Interface> &Registry +#define TILE_DECLARE_OBJECT_DEPENDENCY_REGISTRY(Registry, Interface) \ + extern ::tile::detail::dependency_registry::ObjectRegistry &Registry -#define TILE_DEFINE_OBJECT_DEPENDENCY_REGISTRY(Registry, Interface) \ - ::tile::detail::dependency_registry::ObjectRegistry &Registry = \ - **::tile::internal::LazyInit<::tile::NeverDestroyed< \ - ::tile::detail::dependency_registry::ObjectRegistry>>() +#define TILE_DEFINE_OBJECT_DEPENDENCY_REGISTRY(Registry, Interface) \ + ::tile::detail::dependency_registry::ObjectRegistry &Registry = \ + **::tile::internal::LazyInit< \ + ::tile::NeverDestroyed<::tile::detail::dependency_registry::ObjectRegistry>>() -#define TILE_REGISTER_OBJECT_DEPENDENCY(Registry, ObjectName, \ - PointerOrFactory) \ - __attribute__((constructor)) static void TILE_INTERNAL_PP_CAT( \ - tile_reserved_registry_dependency_object_register_, __COUNTER__)() { \ - auto registry = ::tile::internal::LazyInit<::tile::NeverDestroyed< \ - typename std::decay::type>>() \ - ->Get(); \ - ::tile::detail::dependency_registry::AddToRegistry(registry, ObjectName, \ - PointerOrFactory); \ - } +#define TILE_REGISTER_OBJECT_DEPENDENCY(Registry, ObjectName, PointerOrFactory) \ + __attribute__((constructor)) static void TILE_INTERNAL_PP_CAT( \ + tile_reserved_registry_dependency_object_register_, __COUNTER__)() \ + { \ + auto registry = \ + ::tile::internal::LazyInit<::tile::NeverDestroyed::type>>() \ + ->Get(); \ + ::tile::detail::dependency_registry::AddToRegistry(registry, ObjectName, PointerOrFactory); \ + } namespace tile { namespace detail { namespace dependency_registry { -#define TILE_REGISTER_CLASS_DEPENDENCY_FUNCTION_AUX_INVOKE(Interface, ...) \ - ::tile::detail::dependency_registry::FactoryAux -template -std::unique_ptr FactoryAux(Args &&...args) { - return make_unique(std::forward(args)...); +#define TILE_REGISTER_CLASS_DEPENDENCY_FUNCTION_AUX_INVOKE(Interface, ...) \ + ::tile::detail::dependency_registry::FactoryAux + +template +std::unique_ptr +FactoryAux(Args &&...args) +{ + return make_unique(std::forward(args)...); } -template -void AddToRegistry(T *registry, Args &&...args) { - registry->Register(std::forward(args)...); +template +void +AddToRegistry(T *registry, Args &&...args) +{ + registry->Register(std::forward(args)...); } -template +template class ClassRegistry { - using Factory = std::function(FactoryArgs...)>; + using Factory = std::function(FactoryArgs...)>; public: - Factory TryGetFactory(Slice name) const noexcept { - auto iter = factories_.find(name.ToString()); - if (iter == factories_.end()) { - return nullptr; + Factory TryGetFactory(Slice name) const noexcept + { + auto iter = factories_.find(name.ToString()); + if (iter == factories_.end()) { return nullptr; } + + auto constructor_ptr = iter->second.get(); + return + [constructor_ptr](FactoryArgs... args) { return (*constructor_ptr)(std::forward(args)...); }; } - auto constructor_ptr = iter->second.get(); - return [constructor_ptr](FactoryArgs... args) { - return (*constructor_ptr)(std::forward(args)...); + Factory GetFactory(const std::string &name) const noexcept + { + auto result = TryGetFactory(name); + TILE_CHECK(result, "Class [{}] implement interface [{}] is not found.", name, GetTypeName()); + + return result; + } + + std::unique_ptr TryNew(Slice name, FactoryArgs... args) const + { + auto iter = factories_.find(name.ToString()); + if (iter == factories_.end()) { return nullptr; } + + auto &constructor = iter->second; + return (*constructor)(std::forward(args)...); + } + + std::unique_ptr New(const std::string &name, FactoryArgs... args) const + { + auto result = TryNew(name, std::forward(args)...); + TILE_CHECK(result, "Class [{}] implement interface [{}] is not found.", name, GetTypeName()); + return result; + } + +private: + template + friend void AddToRegistry(T *registry, Args &&...args); + + void Register(const std::string &name, Factory factory) + { + TILE_CHECK(factories_.find(name) == factories_.end(), "Duplicate class dependency: "); + factories_[name] = make_unique(std::move(factory)); + } + +private: + std::unordered_map> factories_; +}; + +template +class ObjectRegistry { +public: + Interface *TryGet(Slice name) const + { + auto iter = objects_.find(name.ToString()); + if (iter == objects_.end()) { return nullptr; } + auto &&e = *iter->second; + std::call_once(e.flag, [&] { e.object = e.initializer(); }); + return e.object.Get(); + } + + Interface *Get(Slice name) const + { + auto result = TryGet(name); + TILE_CHECK(result, "Object dependency [{}] implementing interface [{}] is not found", name, + GetTypeName()); + return result; + } + +private: + template + friend void AddToRegistry(T *registry, Args &&...args); + + void Register(const std::string &name, Interface *object) + { + TILE_DCHECK(objects_.find(name) == objects_.end()); + auto &&e = objects_[name]; + e = make_unique(); + std::call_once(e->flag, [&] { e->object = MaybeOwning(non_owning, object); }); + } + + void Register(const std::string &name, std::function()> initializer) + { + TILE_CHECK(objects_.find(name) == objects_.end(), "Double registration of object dependency [{}]", name); + + objects_[name] = make_unique(); + objects_[name]->initializer = std::move(initializer); + } + +private: + struct LazilyInstantiatedObject { + std::once_flag flag; + MaybeOwning object; + std::function()> initializer; }; - } - Factory GetFactory(const std::string &name) const noexcept { - auto result = TryGetFactory(name); - TILE_CHECK(result, "Class [{}] implement interface [{}] is not found.", - name, GetTypeName()); - - return result; - } - - std::unique_ptr TryNew(Slice name, FactoryArgs... args) const { - auto iter = factories_.find(name.ToString()); - if (iter == factories_.end()) { - return nullptr; - } - - auto &constructor = iter->second; - return (*constructor)(std::forward(args)...); - } - - std::unique_ptr New(const std::string &name, - FactoryArgs... args) const { - auto result = TryNew(name, std::forward(args)...); - TILE_CHECK(result, "Class [{}] implement interface [{}] is not found.", - name, GetTypeName()); - return result; - } - -private: - template - friend void AddToRegistry(T *registry, Args &&...args); - - void Register(const std::string &name, Factory factory) { - TILE_CHECK(factories_.find(name) == factories_.end(), - "Duplicate class dependency: "); - factories_[name] = make_unique(std::move(factory)); - } - -private: - std::unordered_map> factories_; + std::unordered_map> objects_; }; -template class ObjectRegistry { -public: - Interface *TryGet(Slice name) const { - auto iter = objects_.find(name.ToString()); - if (iter == objects_.end()) { - return nullptr; - } - auto &&e = *iter->second; - std::call_once(e.flag, [&] { e.object = e.initializer(); }); - return e.object.Get(); - } +}// namespace dependency_registry +}// namespace detail +}// namespace tile - Interface *Get(Slice name) const { - auto result = TryGet(name); - TILE_CHECK( - result, - "Object dependency [{}] implementing interface [{}] is not found", name, - GetTypeName()); - return result; - } - -private: - template - friend void AddToRegistry(T *registry, Args &&...args); - - void Register(const std::string &name, Interface *object) { - TILE_DCHECK(objects_.find(name) == objects_.end()); - auto &&e = objects_[name]; - e = make_unique(); - std::call_once(e->flag, [&] { - e->object = MaybeOwning(non_owning, object); - }); - } - - void Register(const std::string &name, - std::function()> initializer) { - TILE_CHECK(objects_.find(name) == objects_.end(), - "Double registration of object dependency [{}]", name); - - objects_[name] = make_unique(); - objects_[name]->initializer = std::move(initializer); - } - -private: - struct LazilyInstantiatedObject { - std::once_flag flag; - MaybeOwning object; - std::function()> initializer; - }; - - std::unordered_map> - objects_; -}; - -} // namespace dependency_registry -} // namespace detail -} // namespace tile - -#endif // TILE_BASE_DEPENDENCY_REGISTRY_H +#endif// TILE_BASE_DEPENDENCY_REGISTRY_H diff --git a/tile/base/dependency_registry_test.cc b/tile/base/dependency_registry_test.cc index 89f7164..df2c3ff 100644 --- a/tile/base/dependency_registry_test.cc +++ b/tile/base/dependency_registry_test.cc @@ -1,77 +1,84 @@ #include "tile/base/dependency_registry.h" #include "gtest/gtest.h" + namespace tile { struct Destroyer { - virtual ~Destroyer() = default; + virtual ~Destroyer() = default; }; struct FastDestroyer : Destroyer { - FastDestroyer() { ++instances; } - ~FastDestroyer() override { --instances; } - static int instances; + FastDestroyer() { ++instances; } + + ~FastDestroyer() override { --instances; } + + static int instances; }; + int FastDestroyer::instances = 0; struct GentleDestroyer : Destroyer { - GentleDestroyer() { ++instances; } - ~GentleDestroyer() override { --instances; } - static int instances; + GentleDestroyer() { ++instances; } + + ~GentleDestroyer() override { --instances; } + + static int instances; }; + int GentleDestroyer::instances = 0; struct SpeedDestroyer : Destroyer { - explicit SpeedDestroyer(int) {} + explicit SpeedDestroyer(int) {} }; + struct SpeedDestroyer2 : Destroyer {}; TILE_DECLARE_CLASS_DEPENDENCY_REGISTRY(world_destroyer, Destroyer); TILE_DEFINE_CLASS_DEPENDENCY_REGISTRY(world_destroyer, Destroyer); -TILE_REGISTER_CLASS_DEPENDENCY(world_destroyer, "fast-destroyer", - FastDestroyer); +TILE_REGISTER_CLASS_DEPENDENCY(world_destroyer, "fast-destroyer", FastDestroyer); TILE_REGISTER_CLASS_DEPENDENCY_FACTORY(world_destroyer, "gentle-destroyer", [] { - return make_unique(); + return make_unique(); }); GentleDestroyer global_gentle_destroyer; TILE_DECLARE_CLASS_DEPENDENCY_REGISTRY(with_arg_destroyer, Destroyer, int); TILE_DEFINE_CLASS_DEPENDENCY_REGISTRY(with_arg_destroyer, Destroyer, int); -TILE_REGISTER_CLASS_DEPENDENCY(with_arg_destroyer, "speed-destroyer", - SpeedDestroyer, int); -TILE_REGISTER_CLASS_DEPENDENCY_FACTORY(with_arg_destroyer, "speed-destroyer-2", - [](int speed) { - return make_unique(); - }); +TILE_REGISTER_CLASS_DEPENDENCY(with_arg_destroyer, "speed-destroyer", SpeedDestroyer, int); +TILE_REGISTER_CLASS_DEPENDENCY_FACTORY(with_arg_destroyer, "speed-destroyer-2", [](int speed) { + return make_unique(); +}); -TEST(DependencyRegistry, Class) { - EXPECT_TRUE(world_destroyer.TryGetFactory("gentle-destroyer")); - EXPECT_TRUE(world_destroyer.TryGetFactory("fast-destroyer")); - EXPECT_FALSE(world_destroyer.TryGetFactory("404-destroyer")); - EXPECT_TRUE(world_destroyer.TryNew("gentle-destroyer")); - EXPECT_TRUE(world_destroyer.TryNew("fast-destroyer")); - EXPECT_FALSE(world_destroyer.TryGetFactory("404-destroyer")); +TEST(DependencyRegistry, Class) +{ + EXPECT_TRUE(world_destroyer.TryGetFactory("gentle-destroyer")); + EXPECT_TRUE(world_destroyer.TryGetFactory("fast-destroyer")); + EXPECT_FALSE(world_destroyer.TryGetFactory("404-destroyer")); + EXPECT_TRUE(world_destroyer.TryNew("gentle-destroyer")); + EXPECT_TRUE(world_destroyer.TryNew("fast-destroyer")); + EXPECT_FALSE(world_destroyer.TryGetFactory("404-destroyer")); - EXPECT_EQ(1, GentleDestroyer::instances); // The global one. - EXPECT_EQ(0, FastDestroyer::instances); - - { - auto gentle = world_destroyer.TryNew("gentle-destroyer"); - EXPECT_EQ(2, GentleDestroyer::instances); + EXPECT_EQ(1, GentleDestroyer::instances);// The global one. + EXPECT_EQ(0, FastDestroyer::instances); + + { + auto gentle = world_destroyer.TryNew("gentle-destroyer"); + EXPECT_EQ(2, GentleDestroyer::instances); + EXPECT_EQ(0, FastDestroyer::instances); + auto fast = world_destroyer.TryNew("fast-destroyer"); + EXPECT_EQ(2, GentleDestroyer::instances); + EXPECT_EQ(1, FastDestroyer::instances); + } + EXPECT_EQ(1, GentleDestroyer::instances); EXPECT_EQ(0, FastDestroyer::instances); - auto fast = world_destroyer.TryNew("fast-destroyer"); - EXPECT_EQ(2, GentleDestroyer::instances); - EXPECT_EQ(1, FastDestroyer::instances); - } - EXPECT_EQ(1, GentleDestroyer::instances); - EXPECT_EQ(0, FastDestroyer::instances); } -TEST(DependencyRegistry, ClassWithArgs) { - EXPECT_TRUE(with_arg_destroyer.TryGetFactory("speed-destroyer")); - EXPECT_TRUE(with_arg_destroyer.TryGetFactory("speed-destroyer-2")); - EXPECT_FALSE(with_arg_destroyer.TryGetFactory("speed-destroyer-3")); - EXPECT_TRUE(with_arg_destroyer.TryNew("speed-destroyer", 456)); - EXPECT_TRUE(with_arg_destroyer.TryNew("speed-destroyer-2", 456)); - EXPECT_FALSE(with_arg_destroyer.TryNew("speed-destroyer-3", 456)); +TEST(DependencyRegistry, ClassWithArgs) +{ + EXPECT_TRUE(with_arg_destroyer.TryGetFactory("speed-destroyer")); + EXPECT_TRUE(with_arg_destroyer.TryGetFactory("speed-destroyer-2")); + EXPECT_FALSE(with_arg_destroyer.TryGetFactory("speed-destroyer-3")); + EXPECT_TRUE(with_arg_destroyer.TryNew("speed-destroyer", 456)); + EXPECT_TRUE(with_arg_destroyer.TryNew("speed-destroyer-2", 456)); + EXPECT_FALSE(with_arg_destroyer.TryNew("speed-destroyer-3", 456)); } -} // namespace tile +}// namespace tile diff --git a/tile/base/down_cast.h b/tile/base/down_cast.h index fa5ed7a..bde1421 100644 --- a/tile/base/down_cast.h +++ b/tile/base/down_cast.h @@ -8,18 +8,22 @@ #include namespace tile { -template ::value, - const To *, To *>::type> -inline R down_cast(From *ptr) { - TILE_DCHECK(dynamic_cast(ptr)); - return static_cast(ptr); +template::value, const To *, To *>::type> +inline R +down_cast(From *ptr) +{ + TILE_DCHECK(dynamic_cast(ptr)); + return static_cast(ptr); } -template -inline auto down_cast(From &ref) -> decltype(down_cast(&ref)) { - return down_cast(&ref); +template +inline auto +down_cast(From &ref) -> decltype(down_cast(&ref)) +{ + return down_cast(&ref); } -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_DOWN_CAST_H +#endif// _TILE_BASE_DOWN_CAST_H diff --git a/tile/base/down_cast_test.cc b/tile/base/down_cast_test.cc index afde504..57b135d 100644 --- a/tile/base/down_cast_test.cc +++ b/tile/base/down_cast_test.cc @@ -3,22 +3,25 @@ namespace tile { struct A { - virtual ~A() = default; + virtual ~A() = default; }; + struct B : A {}; -TEST(DownCast, All) { - B b; - A *ptr = &b; - ASSERT_NE(nullptr, down_cast(ptr)); - ASSERT_NE(nullptr, down_cast(const_cast(ptr))); +TEST(DownCast, All) +{ + B b; + A *ptr = &b; + ASSERT_NE(nullptr, down_cast(ptr)); + ASSERT_NE(nullptr, down_cast(const_cast(ptr))); } #ifndef NDEBUG -TEST(CastDeathTest, DownCast) { - A a; - A *ptr = &a; - ASSERT_DEATH(down_cast(ptr), ""); +TEST(CastDeathTest, DownCast) +{ + A a; + A *ptr = &a; + ASSERT_DEATH(down_cast(ptr), ""); } #endif -} // namespace tile +}// namespace tile diff --git a/tile/base/encoding.h b/tile/base/encoding.h index 827dabf..698e337 100644 --- a/tile/base/encoding.h +++ b/tile/base/encoding.h @@ -7,4 +7,4 @@ #include "tile/base/encoding/hex.h" #include "tile/base/encoding/percent.h" -#endif // _TILE_BASE_ENCODING_H +#endif// _TILE_BASE_ENCODING_H diff --git a/tile/base/encoding/base64.cc b/tile/base/encoding/base64.cc index 98f536c..490645d 100644 --- a/tile/base/encoding/base64.cc +++ b/tile/base/encoding/base64.cc @@ -19,137 +19,132 @@ static constexpr std::size_t kBufferSize = BLOCK_SIZE_1M; #undef BLOCK_SIZE_64K #undef BLOCK_SIZE_1M -} // namespace +}// namespace -std::string EncodeBase64(Slice from) { - std::string result; - EncodeBase64(from, &result); - return result; -} -std::optional DecodeBase64(Slice from) { - std::string result; - if (!DecodeBase64(from, &result)) { - return std::nullopt; - } - return result; +std::string +EncodeBase64(Slice from) +{ + std::string result; + EncodeBase64(from, &result); + return result; } -void EncodeBase64(Slice from, std::string *to) { - TILE_CHECK(from.size() < std::numeric_limits::max(), - "Not implemented: Source bytes too long. {} > max_size({})", - from.size(), std::numeric_limits::max()); - - const auto size = 4 * ((from.size() + 2) / 3); - to->resize(size); - base64_encodestate state; - base64_init_encodestate(&state); - - std::size_t used = 0; - std::size_t input_len; - while (!from.empty()) { - input_len = std::min(kBufferSize, from.size()); - used += base64_encode_block( - reinterpret_cast(from.data()), input_len, - reinterpret_cast(internal::RemoveConstPtr(to->data())) + used, - &state); - from.RemovePrefix(input_len); - }; - base64_encode_blockend( - reinterpret_cast(internal::RemoveConstPtr(to->data())) + used, - &state); - - // bool success = - // Base64::Encode(from.data(), from.size(), - // internal::RemoveConstPtr(to->data()), to->size()); - // TILE_CHECK(success, "Unexpected: Failed to do base64-encode."); +std::optional +DecodeBase64(Slice from) +{ + std::string result; + if (!DecodeBase64(from, &result)) { return std::nullopt; } + return result; } -bool DecodeBase64(Slice from, std::string *to) { - if (TILE_UNLIKELY(from.empty())) { - to->clear(); - return true; - } +void +EncodeBase64(Slice from, std::string *to) +{ + TILE_CHECK(from.size() < std::numeric_limits::max(), + "Not implemented: Source bytes too long. {} > max_size({})", from.size(), + std::numeric_limits::max()); - std::string safe_from_str; - // auto padding - auto padding = (4 - from.size() % 4) % 4; - if (padding > 2) { - return false; - } else if (padding != 0) { - TILE_LOG_WARNING("`from.size()` [{}] Can not be divisible by 4. " - "auto add padding [{}] `=`", - from.size(), padding); - safe_from_str = from.ToString() + std::string(padding, '='); - from = safe_from_str; - } + const auto size = 4 * ((from.size() + 2) / 3); + to->resize(size); + base64_encodestate state; + base64_init_encodestate(&state); - auto size = 3 * from.size() / 4; - to->resize(size); - - { - Slice input = from; - base64_decodestate state; - base64_init_decodestate(&state); std::size_t used = 0; - while (!input.empty()) { - auto input_len = std::min(kBufferSize, from.size()); - auto encoded_len = base64_decode_block( - input.data(), input_len, - reinterpret_cast(internal::RemoveConstPtr(to->data())) + used, - &state); - if (TILE_UNLIKELY(encoded_len == 0)) { - return false; - } - used += encoded_len; - input.RemovePrefix(input_len); - } - } + std::size_t input_len; + while (!from.empty()) { + input_len = std::min(kBufferSize, from.size()); + used += base64_encode_block(reinterpret_cast(from.data()), input_len, + reinterpret_cast(internal::RemoveConstPtr(to->data())) + used, &state); + from.RemovePrefix(input_len); + }; + base64_encode_blockend(reinterpret_cast(internal::RemoveConstPtr(to->data())) + used, &state); - // === Sample - // { - // bool success = - // Base64::Decode(from.data(), from.size(), - // internal::RemoveConstPtr(to->data()), to->size()); - // if (!success) { - // return false; - // } - // } - - // === OpenSSL - // int rc; - // rc = EVP_DecodeBlock( - // reinterpret_cast(internal::RemoveConstPtr(to->data())), reinterpret_cast(from.data()), from.size()); - // if (rc != size) { - // return false; - // } - // - // @sa: https://tools.ietf.org/html/rfc4648#section-4 - // - // (1) The final quantum of encoding input is an integral multiple of 24 - // bits; here, the final unit of encoded output will be an integral - // multiple of 4 characters with no "=" padding. - // - // (2) The final quantum of encoding input is exactly 8 bits; here, the - // final unit of encoded output will be two characters followed by - // two "=" padding characters. - // - // (3) The final quantum of encoding input is exactly 16 bits; here, the - // final unit of encoded output will be three characters followed by - // one "=" padding character. - TILE_CHECK(from.size() >= 2 && to->size() >= 2); - if (from[from.size() - 1] == '=') { - to->pop_back(); - } - - if (from[from.size() - 2] == '=') { - to->pop_back(); - } - - // to->pop_back(); // Remove Terminating null - - return true; + // bool success = + // Base64::Encode(from.data(), from.size(), + // internal::RemoveConstPtr(to->data()), to->size()); + // TILE_CHECK(success, "Unexpected: Failed to do base64-encode."); } -} // namespace tile +bool +DecodeBase64(Slice from, std::string *to) +{ + if (TILE_UNLIKELY(from.empty())) { + to->clear(); + return true; + } + + std::string safe_from_str; + // auto padding + auto padding = (4 - from.size() % 4) % 4; + if (padding > 2) { + return false; + } else if (padding != 0) { + TILE_LOG_WARNING("`from.size()` [{}] Can not be divisible by 4. " + "auto add padding [{}] `=`", + from.size(), padding); + safe_from_str = from.ToString() + std::string(padding, '='); + from = safe_from_str; + } + + auto size = 3 * from.size() / 4; + to->resize(size); + + { + Slice input = from; + base64_decodestate state; + base64_init_decodestate(&state); + std::size_t used = 0; + while (!input.empty()) { + auto input_len = std::min(kBufferSize, from.size()); + auto encoded_len = base64_decode_block( + input.data(), input_len, reinterpret_cast(internal::RemoveConstPtr(to->data())) + used, &state); + if (TILE_UNLIKELY(encoded_len == 0)) { return false; } + used += encoded_len; + input.RemovePrefix(input_len); + } + } + + // === Sample + // { + // bool success = + // Base64::Decode(from.data(), from.size(), + // internal::RemoveConstPtr(to->data()), to->size()); + // if (!success) { + // return false; + // } + // } + + // === OpenSSL + // int rc; + // rc = EVP_DecodeBlock( + // reinterpret_cast(internal::RemoveConstPtr(to->data())), reinterpret_cast(from.data()), from.size()); + // if (rc != size) { + // return false; + // } + // + // @sa: https://tools.ietf.org/html/rfc4648#section-4 + // + // (1) The final quantum of encoding input is an integral multiple of 24 + // bits; here, the final unit of encoded output will be an integral + // multiple of 4 characters with no "=" padding. + // + // (2) The final quantum of encoding input is exactly 8 bits; here, the + // final unit of encoded output will be two characters followed by + // two "=" padding characters. + // + // (3) The final quantum of encoding input is exactly 16 bits; here, the + // final unit of encoded output will be three characters followed by + // one "=" padding character. + TILE_CHECK(from.size() >= 2 && to->size() >= 2); + if (from[from.size() - 1] == '=') { to->pop_back(); } + + if (from[from.size() - 2] == '=') { to->pop_back(); } + + // to->pop_back(); // Remove Terminating null + + return true; +} + +}// namespace tile diff --git a/tile/base/encoding/base64.h b/tile/base/encoding/base64.h index 09a19ae..87a3c68 100644 --- a/tile/base/encoding/base64.h +++ b/tile/base/encoding/base64.h @@ -13,6 +13,6 @@ std::optional DecodeBase64(Slice from); void EncodeBase64(Slice from, std::string *to); bool DecodeBase64(Slice from, std::string *to); -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_ENCODING_BASE64_H +#endif// _TILE_BASE_ENCODING_BASE64_H diff --git a/tile/base/encoding/base64_test.cc b/tile/base/encoding/base64_test.cc index 7996f52..b851bbf 100644 --- a/tile/base/encoding/base64_test.cc +++ b/tile/base/encoding/base64_test.cc @@ -9,70 +9,75 @@ namespace tile { -static constexpr auto kText = ".<>@????????"; -static constexpr auto kBase64Text = "Ljw+QD8/Pz8/Pz8/"; -static constexpr auto kText2 = ".<>@???????"; +static constexpr auto kText = ".<>@????????"; +static constexpr auto kBase64Text = "Ljw+QD8/Pz8/Pz8/"; +static constexpr auto kText2 = ".<>@???????"; static constexpr auto kBase64Text2 = "Ljw+QD8/Pz8/Pz8="; -TEST(Base64, Default) { - EXPECT_EQ(kBase64Text, EncodeBase64(kText)); - auto decoded = DecodeBase64(kBase64Text); - ASSERT_TRUE(decoded); - EXPECT_EQ(kText, *decoded); - EXPECT_FALSE(DecodeBase64("some-invalid-base64-encoded!!")); -} - -TEST(Base64, Padding) { - EXPECT_EQ(kBase64Text2, EncodeBase64(kText2)); - - auto decoded = DecodeBase64(kBase64Text2); - ASSERT_TRUE(decoded); - EXPECT_EQ(kText2, *decoded); -} - -TEST(Base64, Empty) { - EXPECT_EQ("", EncodeBase64("")); - auto decoded = DecodeBase64(""); - ASSERT_TRUE(decoded); - EXPECT_EQ("", *decoded); -} - -TEST(Base64, AutoPadding) { - static constexpr auto kChar = "A"; - - EXPECT_EQ("QQ==", EncodeBase64(kChar)); - - { - auto decoded = DecodeBase64("QQ=="); +TEST(Base64, Default) +{ + EXPECT_EQ(kBase64Text, EncodeBase64(kText)); + auto decoded = DecodeBase64(kBase64Text); ASSERT_TRUE(decoded); - EXPECT_EQ(kChar, *decoded); - } - - // auto padding, 1 - { - auto decoded1 = DecodeBase64("QQ="); - ASSERT_TRUE(decoded1); - EXPECT_EQ(kChar, *decoded1); - } - - // auto padding, 2 - { - auto decoded2 = DecodeBase64("QQ"); - ASSERT_TRUE(decoded2); - EXPECT_EQ(kChar, *decoded2); - } + EXPECT_EQ(kText, *decoded); + EXPECT_FALSE(DecodeBase64("some-invalid-base64-encoded!!")); } -TEST(Base64, Torture) { - std::string random_str; - std::string encoded; - std::string decoded; - for (int i = 0; i != 1000; ++i) { - testing::RandomString(&random_str, 10000, 10000); - EncodeBase64(random_str, &encoded); - ASSERT_TRUE(DecodeBase64(encoded, &decoded)); - EXPECT_EQ(random_str, decoded); - } +TEST(Base64, Padding) +{ + EXPECT_EQ(kBase64Text2, EncodeBase64(kText2)); + + auto decoded = DecodeBase64(kBase64Text2); + ASSERT_TRUE(decoded); + EXPECT_EQ(kText2, *decoded); } -} // namespace tile +TEST(Base64, Empty) +{ + EXPECT_EQ("", EncodeBase64("")); + auto decoded = DecodeBase64(""); + ASSERT_TRUE(decoded); + EXPECT_EQ("", *decoded); +} + +TEST(Base64, AutoPadding) +{ + static constexpr auto kChar = "A"; + + EXPECT_EQ("QQ==", EncodeBase64(kChar)); + + { + auto decoded = DecodeBase64("QQ=="); + ASSERT_TRUE(decoded); + EXPECT_EQ(kChar, *decoded); + } + + // auto padding, 1 + { + auto decoded1 = DecodeBase64("QQ="); + ASSERT_TRUE(decoded1); + EXPECT_EQ(kChar, *decoded1); + } + + // auto padding, 2 + { + auto decoded2 = DecodeBase64("QQ"); + ASSERT_TRUE(decoded2); + EXPECT_EQ(kChar, *decoded2); + } +} + +TEST(Base64, Torture) +{ + std::string random_str; + std::string encoded; + std::string decoded; + for (int i = 0; i != 1000; ++i) { + testing::RandomString(&random_str, 10000, 10000); + EncodeBase64(random_str, &encoded); + ASSERT_TRUE(DecodeBase64(encoded, &decoded)); + EXPECT_EQ(random_str, decoded); + } +} + +}// namespace tile diff --git a/tile/base/encoding/detail/base64_impl.h b/tile/base/encoding/detail/base64_impl.h index 6e8034f..e3ba4cd 100644 --- a/tile/base/encoding/detail/base64_impl.h +++ b/tile/base/encoding/detail/base64_impl.h @@ -3,286 +3,247 @@ #include -const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; +const char kBase64Alphabet[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; namespace { -static inline unsigned char b64_lookup_aux(unsigned char c) { - if (c >= 'A' && c <= 'Z') - return c - 'A'; - if (c >= 'a' && c <= 'z') - return c - 71; - if (c >= '0' && c <= '9') - return c + 4; - if (c == '+') - return 62; - if (c == '/') - return 63; - return 255; +static inline unsigned char +b64_lookup_aux(unsigned char c) +{ + if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 71; + if (c >= '0' && c <= '9') return c + 4; + if (c == '+') return 62; + if (c == '/') return 63; + return 255; } -struct Base64LookupInitializer { - Base64LookupInitializer() { - for (int i = 0; i < 256; i++) { - kBase64Lookup[i] = b64_lookup_aux(i); - } - } - int kBase64Lookup[256]; +struct Base64LookupInitializer { + Base64LookupInitializer() + { + for (int i = 0; i < 256; i++) { kBase64Lookup[i] = b64_lookup_aux(i); } + } + + int kBase64Lookup[256]; }; -static inline unsigned char b64_lookup_aux1(unsigned char c) { - static Base64LookupInitializer init; - return init.kBase64Lookup[c]; +static inline unsigned char +b64_lookup_aux1(unsigned char c) +{ + static Base64LookupInitializer init; + return init.kBase64Lookup[c]; +} +}// namespace + +inline unsigned char +b64_lookup(unsigned char c) +{ + return b64_lookup_aux1(c); } -} // namespace -inline unsigned char b64_lookup(unsigned char c) { return b64_lookup_aux1(c); } class Base64 { public: - static bool Encode(const std::string &in, std::string *out) { - int i = 0, j = 0; - size_t enc_len = 0; - unsigned char a3[3]; - unsigned char a4[4]; + static bool Encode(const std::string &in, std::string *out) + { + int i = 0, j = 0; + size_t enc_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; - out->resize(EncodedLength(in)); + out->resize(EncodedLength(in)); - size_t input_len = in.size(); - std::string::const_iterator input = in.begin(); + size_t input_len = in.size(); + std::string::const_iterator input = in.begin(); - while (input_len--) { - a3[i++] = *(input++); - if (i == 3) { - a3_to_a4(a4, a3); + while (input_len--) { + a3[i++] = *(input++); + if (i == 3) { + a3_to_a4(a4, a3); - for (i = 0; i < 4; i++) { - (*out)[enc_len++] = kBase64Alphabet[a4[i]]; + for (i = 0; i < 4; i++) { (*out)[enc_len++] = kBase64Alphabet[a4[i]]; } + + i = 0; + } } - i = 0; - } - } + if (i) { + for (j = i; j < 3; j++) { a3[j] = '\0'; } - if (i) { - for (j = i; j < 3; j++) { - a3[j] = '\0'; - } + a3_to_a4(a4, a3); - a3_to_a4(a4, a3); + for (j = 0; j < i + 1; j++) { (*out)[enc_len++] = kBase64Alphabet[a4[j]]; } - for (j = 0; j < i + 1; j++) { - (*out)[enc_len++] = kBase64Alphabet[a4[j]]; - } - - while ((i++ < 3)) { - (*out)[enc_len++] = '='; - } - } - - return (enc_len == out->size()); - } - - static bool Encode(const char *input, size_t input_length, char *out, - size_t out_length) { - int i = 0, j = 0; - char *out_begin = out; - unsigned char a3[3]; - unsigned char a4[4]; - - size_t encoded_length = EncodedLength(input_length); - - if (out_length < encoded_length) - return false; - - while (input_length--) { - a3[i++] = *input++; - if (i == 3) { - a3_to_a4(a4, a3); - - for (i = 0; i < 4; i++) { - *out++ = kBase64Alphabet[a4[i]]; - } - // out[0] = kBase64Alphabet[a4[0]]; - // out[1] = kBase64Alphabet[a4[1]]; - // out[2] = kBase64Alphabet[a4[2]]; - // out[3] = kBase64Alphabet[a4[3]]; - // out += 4; - - i = 0; - } - } - - if (i) { - for (j = i; j < 3; j++) { - a3[j] = '\0'; - } - - a3_to_a4(a4, a3); - - for (j = 0; j < i + 1; j++) { - *out++ = kBase64Alphabet[a4[j]]; - } - - while ((i++ < 3)) { - *out++ = '='; - } - } - - return (out == (out_begin + encoded_length)); - } - - static bool Decode(const std::string &in, std::string *out) { - int i = 0, j = 0; - size_t dec_len = 0; - unsigned char a3[3]; - unsigned char a4[4]; - - size_t input_len = in.size(); - std::string::const_iterator input = in.begin(); - - out->resize(DecodedLength(in)); - - while (input_len--) { - if (*input == '=') { - break; - } - - a4[i++] = *(input++); - if (i == 4) { - for (i = 0; i < 4; i++) { - a4[i] = b64_lookup(a4[i]); + while ((i++ < 3)) { (*out)[enc_len++] = '='; } } - a4_to_a3(a3, a4); + return (enc_len == out->size()); + } - for (i = 0; i < 3; i++) { - (*out)[dec_len++] = a3[i]; + static bool Encode(const char *input, size_t input_length, char *out, size_t out_length) + { + int i = 0, j = 0; + char *out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; + + size_t encoded_length = EncodedLength(input_length); + + if (out_length < encoded_length) return false; + + while (input_length--) { + a3[i++] = *input++; + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { *out++ = kBase64Alphabet[a4[i]]; } + // out[0] = kBase64Alphabet[a4[0]]; + // out[1] = kBase64Alphabet[a4[1]]; + // out[2] = kBase64Alphabet[a4[2]]; + // out[3] = kBase64Alphabet[a4[3]]; + // out += 4; + + i = 0; + } } - i = 0; - } - } + if (i) { + for (j = i; j < 3; j++) { a3[j] = '\0'; } - if (i) { - for (j = i; j < 4; j++) { - a4[j] = '\0'; - } + a3_to_a4(a4, a3); - for (j = 0; j < 4; j++) { - a4[j] = b64_lookup(a4[j]); - } + for (j = 0; j < i + 1; j++) { *out++ = kBase64Alphabet[a4[j]]; } - a4_to_a3(a3, a4); - - for (j = 0; j < i - 1; j++) { - (*out)[dec_len++] = a3[j]; - } - } - - return (dec_len == out->size()); - } - - static bool Decode(const char *input, size_t input_length, char *out, - size_t out_length) { - int i = 0, j = 0; - char *out_begin = out; - unsigned char a3[3]; - unsigned char a4[4]; - - size_t decoded_length = DecodedLength(input, input_length); - - if (out_length < decoded_length) - return false; - - while (input_length--) { - if (*input == '=') { - break; - } - - a4[i++] = *(input++); - if (i == 4) { - for (i = 0; i < 4; i++) { - a4[i] = b64_lookup(a4[i]); + while ((i++ < 3)) { *out++ = '='; } } - a4_to_a3(a3, a4); + return (out == (out_begin + encoded_length)); + } - for (i = 0; i < 3; i++) { - *out++ = a3[i]; + static bool Decode(const std::string &in, std::string *out) + { + int i = 0, j = 0; + size_t dec_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + size_t input_len = in.size(); + std::string::const_iterator input = in.begin(); + + out->resize(DecodedLength(in)); + + while (input_len--) { + if (*input == '=') { break; } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i < 4; i++) { a4[i] = b64_lookup(a4[i]); } + + a4_to_a3(a3, a4); + + for (i = 0; i < 3; i++) { (*out)[dec_len++] = a3[i]; } + + i = 0; + } } - i = 0; - } + if (i) { + for (j = i; j < 4; j++) { a4[j] = '\0'; } + + for (j = 0; j < 4; j++) { a4[j] = b64_lookup(a4[j]); } + + a4_to_a3(a3, a4); + + for (j = 0; j < i - 1; j++) { (*out)[dec_len++] = a3[j]; } + } + + return (dec_len == out->size()); } - if (i) { - for (j = i; j < 4; j++) { - a4[j] = '\0'; - } + static bool Decode(const char *input, size_t input_length, char *out, size_t out_length) + { + int i = 0, j = 0; + char *out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; - for (j = 0; j < 4; j++) { - a4[j] = b64_lookup(a4[j]); - } + size_t decoded_length = DecodedLength(input, input_length); - a4_to_a3(a3, a4); + if (out_length < decoded_length) return false; - for (j = 0; j < i - 1; j++) { - *out++ = a3[j]; - } + while (input_length--) { + if (*input == '=') { break; } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i < 4; i++) { a4[i] = b64_lookup(a4[i]); } + + a4_to_a3(a3, a4); + + for (i = 0; i < 3; i++) { *out++ = a3[i]; } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { a4[j] = '\0'; } + + for (j = 0; j < 4; j++) { a4[j] = b64_lookup(a4[j]); } + + a4_to_a3(a3, a4); + + for (j = 0; j < i - 1; j++) { *out++ = a3[j]; } + } + + return (out == (out_begin + decoded_length)); } - return (out == (out_begin + decoded_length)); - } + static size_t DecodedLength(const char *in, size_t in_length) + { + int numEq = 0; - static size_t DecodedLength(const char *in, size_t in_length) { - int numEq = 0; + const char *in_end = in + in_length; + while (*--in_end == '=') ++numEq; - const char *in_end = in + in_length; - while (*--in_end == '=') - ++numEq; - - return ((6 * in_length) / 8) - numEq; - } - - static size_t DecodedLength(const std::string &in) { - int numEq = 0; - size_t n = in.size(); - - for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; - ++it) { - ++numEq; + return ((6 * in_length) / 8) - numEq; } - return ((6 * n) / 8) - numEq; - } + static size_t DecodedLength(const std::string &in) + { + int numEq = 0; + size_t n = in.size(); - inline static size_t EncodedLength(size_t length) { - return (length + 2 - ((length + 2) % 3)) / 3 * 4; - } + for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { ++numEq; } - inline static size_t EncodedLength(const std::string &in) { - return EncodedLength(in.length()); - } + return ((6 * n) / 8) - numEq; + } - inline static void StripPadding(std::string *in) { - while (!in->empty() && *(in->rbegin()) == '=') - in->resize(in->size() - 1); - } + inline static size_t EncodedLength(size_t length) { return (length + 2 - ((length + 2) % 3)) / 3 * 4; } + + inline static size_t EncodedLength(const std::string &in) { return EncodedLength(in.length()); } + + inline static void StripPadding(std::string *in) + { + while (!in->empty() && *(in->rbegin()) == '=') in->resize(in->size() - 1); + } private: - static inline void a3_to_a4(unsigned char *a4, unsigned char *a3) { - a4[0] = (a3[0] & 0xfc) >> 2; - a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); - a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); - a4[3] = (a3[2] & 0x3f); - } + static inline void a3_to_a4(unsigned char *a4, unsigned char *a3) + { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = (a3[2] & 0x3f); + } - static inline void a4_to_a3(unsigned char *a3, unsigned char *a4) { - a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); - a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); - a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; - } + static inline void a4_to_a3(unsigned char *a3, unsigned char *a4) + { + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; + } }; -#endif // BASE64_H +#endif// BASE64_H diff --git a/tile/base/encoding/detail/hex_chars.cc b/tile/base/encoding/detail/hex_chars.cc index de6cdab..222c74e 100644 --- a/tile/base/encoding/detail/hex_chars.cc +++ b/tile/base/encoding/detail/hex_chars.cc @@ -6,80 +6,88 @@ namespace detail { namespace { static constexpr auto kCharMin = std::numeric_limits::min(); static constexpr auto kCharMax = std::numeric_limits::max(); -static constexpr auto kSize = kCharMax - kCharMin + 1; +static constexpr auto kSize = kCharMax - kCharMin + 1; -int AsciiCodeFromCharPairSlow(char a, char b) { - a = ToLower(a); - b = ToLower(b); - auto ToNum = [](char x) { - if (x >= '0' && x <= '9') { - return x - '0'; - } else if (x >= 'a' && x <= 'f') { - return x - 'a' + 10; +int +AsciiCodeFromCharPairSlow(char a, char b) +{ + a = ToLower(a); + b = ToLower(b); + auto ToNum = [](char x) { + if (x >= '0' && x <= '9') { + return x - '0'; + } else if (x >= 'a' && x <= 'f') { + return x - 'a' + 10; + } else { + return -1; + } + }; + + int x = ToNum(a); + int y = ToNum(b); + if (x == -1 || y == -1) { return -1; } + + return (x << 4) | y; +} + +std::pair +AsciiCodeToCharPairSlow(std::uint8_t value, bool uppercase) +{ + if (uppercase) { + return std::make_pair(kHexCharsUpper[value >> 4], kHexCharsUpper[value & 0x0f]); } else { - return -1; + return std::make_pair(kHexCharsLower[value >> 4], kHexCharsLower[value & 0x0f]); } - }; - - int x = ToNum(a); - int y = ToNum(b); - if (x == -1 || y == -1) { - return -1; - } - - return (x << 4) | y; } -std::pair AsciiCodeToCharPairSlow(std::uint8_t value, - bool uppercase) { - if (uppercase) { - return std::make_pair(kHexCharsUpper[value >> 4], - kHexCharsUpper[value & 0x0f]); - } else { - return std::make_pair(kHexCharsLower[value >> 4], - kHexCharsLower[value & 0x0f]); - } -} - -std::array, 256> GenAsciiCodeFromCharPairTable() { - std::array, 256> table; - for (char i = kCharMin; i != kCharMax; ++i) { - for (char j = kCharMin; j != kCharMax; ++j) { - table[i - kCharMin][j - kCharMin] = AsciiCodeFromCharPairSlow(i, j); +std::array, 256> +GenAsciiCodeFromCharPairTable() +{ + std::array, 256> table; + for (char i = kCharMin; i != kCharMax; ++i) { + for (char j = kCharMin; j != kCharMax; ++j) { + table[i - kCharMin][j - kCharMin] = AsciiCodeFromCharPairSlow(i, j); + } } - } - return table; + return table; } std::array, 256> -GenAsciiCodeToCharPairTable(bool uppercase) { - std::array, 256> table; - for (int i = 0; i != 256; ++i) { - table[i] = AsciiCodeToCharPairSlow(i, uppercase); - } - return table; +GenAsciiCodeToCharPairTable(bool uppercase) +{ + std::array, 256> table; + for (int i = 0; i != 256; ++i) { table[i] = AsciiCodeToCharPairSlow(i, uppercase); } + return table; } -} // namespace +}// namespace -int AsciiCodeFromCharPair(char a, char b) { - static auto table = GenAsciiCodeFromCharPairTable(); - return table[a - kCharMin][b - kCharMin]; +int +AsciiCodeFromCharPair(char a, char b) +{ + static auto table = GenAsciiCodeFromCharPairTable(); + return table[a - kCharMin][b - kCharMin]; } -inline std::pair AsciiCodeToUpperCharPair(std::uint8_t value) { - static auto table = GenAsciiCodeToCharPairTable(true); - return table[value]; -} -inline std::pair AsciiCodeToLowerCharPair(std::uint8_t value) { - static auto table = GenAsciiCodeToCharPairTable(false); - return table[value]; +inline std::pair +AsciiCodeToUpperCharPair(std::uint8_t value) +{ + static auto table = GenAsciiCodeToCharPairTable(true); + return table[value]; } -std::pair AsciiCodeToCharPair(std::uint8_t value, bool uppercase) { - return uppercase ? AsciiCodeToUpperCharPair(value) - : AsciiCodeToLowerCharPair(value); +inline std::pair +AsciiCodeToLowerCharPair(std::uint8_t value) +{ + static auto table = GenAsciiCodeToCharPairTable(false); + return table[value]; } -} // namespace detail -} // namespace tile +std::pair +AsciiCodeToCharPair(std::uint8_t value, bool uppercase) +{ + return uppercase ? AsciiCodeToUpperCharPair(value) : AsciiCodeToLowerCharPair(value); +} + +}// namespace detail +}// namespace tile diff --git a/tile/base/encoding/detail/hex_chars.h b/tile/base/encoding/detail/hex_chars.h index f29db0a..eca32c7 100644 --- a/tile/base/encoding/detail/hex_chars.h +++ b/tile/base/encoding/detail/hex_chars.h @@ -13,7 +13,7 @@ namespace tile { namespace detail { struct CharPair { - char a, b; + char a, b; }; static constexpr char kHexCharsLower[] = "0123456789abcdef"; @@ -23,10 +23,9 @@ static constexpr char kHexCharsUpper[] = "0123456789ABCDEF"; int AsciiCodeFromCharPair(char a, char b); -std::pair AsciiCodeToCharPair(std::uint8_t value, - bool uppercase = true); +std::pair AsciiCodeToCharPair(std::uint8_t value, bool uppercase = true); -} // namespace detail -} // namespace tile +}// namespace detail +}// namespace tile -#endif // _TILE_BASE_ENCODING_DETAIL_HEX_CHARS_H +#endif// _TILE_BASE_ENCODING_DETAIL_HEX_CHARS_H diff --git a/tile/base/encoding/hex.cc b/tile/base/encoding/hex.cc index 3ed8f36..60ba213 100644 --- a/tile/base/encoding/hex.cc +++ b/tile/base/encoding/hex.cc @@ -6,48 +6,49 @@ namespace tile { -std::string EncodeHex(Slice from, bool uppercase) { - std::string result; - EncodeHex(from, &result, uppercase); - return result; +std::string +EncodeHex(Slice from, bool uppercase) +{ + std::string result; + EncodeHex(from, &result, uppercase); + return result; } -std::optional DecodeHex(Slice from) { - std::string result; - if (!DecodeHex(from, &result)) { - return std::nullopt; - } - return result; +std::optional +DecodeHex(Slice from) +{ + std::string result; + if (!DecodeHex(from, &result)) { return std::nullopt; } + return result; } -void EncodeHex(Slice from, std::string *to, bool uppercase) { - to->clear(); - to->reserve(from.size() * 2); - for (auto &&e : from) { - // auto index = static_cast(e); - auto pair = - detail::AsciiCodeToCharPair(static_cast(e), uppercase); - to->append({pair.first, pair.second}); - } +void +EncodeHex(Slice from, std::string *to, bool uppercase) +{ + to->clear(); + to->reserve(from.size() * 2); + for (auto &&e : from) { + // auto index = static_cast(e); + auto pair = detail::AsciiCodeToCharPair(static_cast(e), uppercase); + to->append({pair.first, pair.second}); + } } -bool DecodeHex(Slice from, std::string *to) { - if (from.size() % 2 != 0) { - return false; - } +bool +DecodeHex(Slice from, std::string *to) +{ + if (from.size() % 2 != 0) { return false; } - to->clear(); - to->reserve(from.size() / 2); - for (size_t i = 0; i != from.size(); i += 2) { - auto v = detail::AsciiCodeFromCharPair(from[i], from[i + 1]); - if (v == -1) { - return false; + to->clear(); + to->reserve(from.size() / 2); + for (size_t i = 0; i != from.size(); i += 2) { + auto v = detail::AsciiCodeFromCharPair(from[i], from[i + 1]); + if (v == -1) { return false; } + + TILE_CHECK(v >= 0 && v <= 255); + to->push_back(v); } - TILE_CHECK(v >= 0 && v <= 255); - to->push_back(v); - } - - return true; + return true; } -} // namespace tile +}// namespace tile diff --git a/tile/base/encoding/hex.h b/tile/base/encoding/hex.h index 3ecacc8..98d916e 100644 --- a/tile/base/encoding/hex.h +++ b/tile/base/encoding/hex.h @@ -11,6 +11,6 @@ std::optional DecodeHex(Slice from); void EncodeHex(Slice from, std::string *to, bool uppercase = false); bool DecodeHex(Slice from, std::string *to); -} // namespace tile +}// namespace tile -#endif // TILE_BASE_ENCODING_HEX_H +#endif// TILE_BASE_ENCODING_HEX_H diff --git a/tile/base/encoding/hex_test.cc b/tile/base/encoding/hex_test.cc index 1ecf190..879bef7 100644 --- a/tile/base/encoding/hex_test.cc +++ b/tile/base/encoding/hex_test.cc @@ -7,23 +7,25 @@ namespace tile { const char Hex123456FF[] = "\x12\x34\x56\xFF"; -TEST(Hex, Default) { - EXPECT_EQ("123456ff", EncodeHex(Hex123456FF)); - EXPECT_EQ("123456FF", EncodeHex(Hex123456FF, true)); - EXPECT_EQ(Hex123456FF, *DecodeHex("123456ff")); - EXPECT_EQ(Hex123456FF, *DecodeHex("123456FF")); +TEST(Hex, Default) +{ + EXPECT_EQ("123456ff", EncodeHex(Hex123456FF)); + EXPECT_EQ("123456FF", EncodeHex(Hex123456FF, true)); + EXPECT_EQ(Hex123456FF, *DecodeHex("123456ff")); + EXPECT_EQ(Hex123456FF, *DecodeHex("123456FF")); } -TEST(Hex, Random) { - std::string random_str; - std::string encoded; - std::string decoded; - for (int i = 0; i != 1000; ++i) { - testing::RandomString(&random_str); - EncodeHex(random_str, &encoded); - ASSERT_TRUE(DecodeHex(encoded, &decoded)); - EXPECT_EQ(random_str, decoded); - } +TEST(Hex, Random) +{ + std::string random_str; + std::string encoded; + std::string decoded; + for (int i = 0; i != 1000; ++i) { + testing::RandomString(&random_str); + EncodeHex(random_str, &encoded); + ASSERT_TRUE(DecodeHex(encoded, &decoded)); + EXPECT_EQ(random_str, decoded); + } } -} // namespace tile +}// namespace tile diff --git a/tile/base/encoding/percent.cc b/tile/base/encoding/percent.cc index 6efa3f8..a1c86f5 100644 --- a/tile/base/encoding/percent.cc +++ b/tile/base/encoding/percent.cc @@ -7,112 +7,107 @@ namespace tile { // [0-9a-zA-Z] namespace { -std::array GenerateUnescapedCharBitmap(Slice unescaped_chars) { - std::array result{}; - for (auto &&e : unescaped_chars) { - result[e] = true; - } +std::array +GenerateUnescapedCharBitmap(Slice unescaped_chars) +{ + std::array result{}; + for (auto &&e : unescaped_chars) { result[e] = true; } - for (int i = 0; i != 10; ++i) { - result[i + '0'] = true; - } + for (int i = 0; i != 10; ++i) { result[i + '0'] = true; } - for (int i = 0; i != 26; ++i) { - result[i + 'A'] = true; - result[i + 'a'] = true; - } + for (int i = 0; i != 26; ++i) { + result[i + 'A'] = true; + result[i + 'a'] = true; + } - return result; + return result; } const std::array, 2> & -GetUnescapedCharBitmap(const PercentEncodingStyle &style) { - static const std::array, 2> kUnescapedChars[] = { - /* emca262 = */ {GenerateUnescapedCharBitmap("_-,;:!?.'()@*/&#+=~$"), - GenerateUnescapedCharBitmap("_-!.*~'()")}, +GetUnescapedCharBitmap(const PercentEncodingStyle &style) +{ + static const std::array, 2> kUnescapedChars[] = { + /* emca262 = */ {GenerateUnescapedCharBitmap("_-,;:!?.'()@*/&#+=~$"), GenerateUnescapedCharBitmap("_-!.*~'()") }, - /* rfc3986 = */ - {GenerateUnescapedCharBitmap("_-,;:!?.'()[]@*/&#+=~$"), - GenerateUnescapedCharBitmap("_-.~") + /* rfc3986 = */ + {GenerateUnescapedCharBitmap("_-,;:!?.'()[]@*/&#+=~$"), GenerateUnescapedCharBitmap("_-.~") - }, - /* rfc5987 = */ - {GenerateUnescapedCharBitmap("!#$&+-.^_`|~"), - GenerateUnescapedCharBitmap("!#$&+-.^_`|~")}}; + }, + /* rfc5987 = */ + {GenerateUnescapedCharBitmap("!#$&+-.^_`|~"), GenerateUnescapedCharBitmap("!#$&+-.^_`|~")} + }; - return kUnescapedChars[static_cast(style)]; + return kUnescapedChars[static_cast(style)]; } -} // namespace +}// namespace -PercentEncodingOptions::PercentEncodingOptions(PercentEncodingStyle s, bool er) - : style(s), escape_reserved(er) {} +PercentEncodingOptions::PercentEncodingOptions(PercentEncodingStyle s, bool er) : style(s), escape_reserved(er) {} -std::string EncodePercent(Slice from, const PercentEncodingOptions &options) { - std::string result; - EncodePercent(from, &result, options); - return result; -} -std::optional DecodePercent(Slice from, - bool decode_plus_sign_as_whitespace) { - std::string result; - if (DecodePercent(from, &result, decode_plus_sign_as_whitespace)) { +std::string +EncodePercent(Slice from, const PercentEncodingOptions &options) +{ + std::string result; + EncodePercent(from, &result, options); return result; - } - return std::nullopt; } -void EncodePercent(Slice from, std::string *to, - const PercentEncodingOptions &options) { - - auto &&unescaped = - GetUnescapedCharBitmap(options.style)[options.escape_reserved]; - - int escape_char_count = 0; - for (auto &&e : from) { - if (!unescaped[static_cast(e)]) { - ++escape_char_count; - } - } - - to->clear(); - to->reserve(from.size() + escape_char_count * 2); - - for (auto &&e : from) { - if (TILE_UNLIKELY(unescaped[static_cast(e)])) { - to->push_back(e); - } else { - auto hex_pair = detail::AsciiCodeToCharPair(static_cast(e)); - to->append({'%', hex_pair.first, hex_pair.second}); - } - } +std::optional +DecodePercent(Slice from, bool decode_plus_sign_as_whitespace) +{ + std::string result; + if (DecodePercent(from, &result, decode_plus_sign_as_whitespace)) { return result; } + return std::nullopt; } -bool DecodePercent(Slice from, std::string *to, - bool decode_plus_sign_as_whitespace) { - to->clear(); - to->reserve(from.size()); - for (auto iter = from.begin(); iter != from.end();) { - if (*iter == '%') { - if (iter + 3 > from.end()) { - return false; - } - auto v = detail::AsciiCodeFromCharPair(*(iter + 1), *(iter + 2)); - if (TILE_LIKELY(v != -1)) { - to->push_back(v); - iter += 3; - } else { - // invalid char - return false; - } - } else { - if (decode_plus_sign_as_whitespace && *iter == '+') { - to->push_back(' '); - ++iter; - } else { - to->push_back(*iter++); - } +void +EncodePercent(Slice from, std::string *to, const PercentEncodingOptions &options) +{ + + auto &&unescaped = GetUnescapedCharBitmap(options.style)[options.escape_reserved]; + + int escape_char_count = 0; + for (auto &&e : from) { + if (!unescaped[static_cast(e)]) { ++escape_char_count; } + } + + to->clear(); + to->reserve(from.size() + escape_char_count * 2); + + for (auto &&e : from) { + if (TILE_UNLIKELY(unescaped[static_cast(e)])) { + to->push_back(e); + } else { + auto hex_pair = detail::AsciiCodeToCharPair(static_cast(e)); + to->append({'%', hex_pair.first, hex_pair.second}); + } } - } - return true; } -} // namespace tile + +bool +DecodePercent(Slice from, std::string *to, bool decode_plus_sign_as_whitespace) +{ + to->clear(); + to->reserve(from.size()); + for (auto iter = from.begin(); iter != from.end();) { + if (*iter == '%') { + if (iter + 3 > from.end()) { return false; } + auto v = detail::AsciiCodeFromCharPair(*(iter + 1), *(iter + 2)); + if (TILE_LIKELY(v != -1)) { + to->push_back(v); + iter += 3; + } else { + // invalid char + return false; + } + } else { + if (decode_plus_sign_as_whitespace && *iter == '+') { + to->push_back(' '); + ++iter; + } else { + to->push_back(*iter++); + } + } + } + return true; +} +}// namespace tile diff --git a/tile/base/encoding/percent.h b/tile/base/encoding/percent.h index cd9343d..f029a8b 100644 --- a/tile/base/encoding/percent.h +++ b/tile/base/encoding/percent.h @@ -9,32 +9,28 @@ namespace tile { enum class PercentEncodingStyle { - Ecma262 = 0, - Rfc3986 = 1, - Rfc5987 = 2, + Ecma262 = 0, + Rfc3986 = 1, + Rfc5987 = 2, }; struct PercentEncodingOptions { - PercentEncodingStyle style = PercentEncodingStyle::Rfc3986; - bool escape_reserved = true; + PercentEncodingStyle style = PercentEncodingStyle::Rfc3986; + bool escape_reserved = true; - PercentEncodingOptions(PercentEncodingStyle s = PercentEncodingStyle::Rfc3986, - bool escape_reserved = true); + PercentEncodingOptions(PercentEncodingStyle s = PercentEncodingStyle::Rfc3986, bool escape_reserved = true); }; std::string EncodePercent(Slice from, - const PercentEncodingOptions &options = - internal::EarlyInitConstant()); -std::optional -DecodePercent(Slice from, bool decode_plus_sign_as_whitespace = false); + const PercentEncodingOptions &options = internal::EarlyInitConstant()); +std::optional DecodePercent(Slice from, bool decode_plus_sign_as_whitespace = false); -void EncodePercent(Slice from, std::string *to, - const PercentEncodingOptions &options = - internal::EarlyInitConstant()); -bool DecodePercent(Slice from, std::string *to, - bool decode_plus_sign_as_whitespace = false); +void EncodePercent(Slice from, + std::string *to, + const PercentEncodingOptions &options = internal::EarlyInitConstant()); +bool DecodePercent(Slice from, std::string *to, bool decode_plus_sign_as_whitespace = false); -} // namespace tile +}// namespace tile -#endif // TILE_BASE_ENCODING_PERCENT_H +#endif// TILE_BASE_ENCODING_PERCENT_H diff --git a/tile/base/encoding/percent_test.cc b/tile/base/encoding/percent_test.cc index 94edabe..488fc6a 100644 --- a/tile/base/encoding/percent_test.cc +++ b/tile/base/encoding/percent_test.cc @@ -6,103 +6,97 @@ namespace tile { -TEST(PercentEncoding, Emca262) { - // Shamelessly copied from: - // - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent - Slice set1 = ";,/?:@&=+$"; // Reserved Characters - Slice set2 = "-_.!~*'()"; // Unescaped Characters - Slice set3 = "#"; // Number Sign - Slice set4 = "ABC abc 123"; // Alphanumeric Characters + Space +TEST(PercentEncoding, Emca262) +{ + // Shamelessly copied from: + // + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent + Slice set1 = ";,/?:@&=+$"; // Reserved Characters + Slice set2 = "-_.!~*'()"; // Unescaped Characters + Slice set3 = "#"; // Number Sign + Slice set4 = "ABC abc 123";// Alphanumeric Characters + Space - // Reserved chars are escaped. - const PercentEncodingOptions ecma262_reversed(PercentEncodingStyle::Ecma262, - true); + // Reserved chars are escaped. + const PercentEncodingOptions ecma262_reversed(PercentEncodingStyle::Ecma262, true); - EXPECT_EQ("%3B%2C%2F%3F%3A%40%26%3D%2B%24", - EncodePercent(set1, ecma262_reversed)); - EXPECT_EQ("-_.!~*'()", EncodePercent(set2, ecma262_reversed)); - EXPECT_EQ("%23", EncodePercent(set3, ecma262_reversed)); - EXPECT_EQ("ABC%20abc%20123", EncodePercent(set4, ecma262_reversed)); + EXPECT_EQ("%3B%2C%2F%3F%3A%40%26%3D%2B%24", EncodePercent(set1, ecma262_reversed)); + EXPECT_EQ("-_.!~*'()", EncodePercent(set2, ecma262_reversed)); + EXPECT_EQ("%23", EncodePercent(set3, ecma262_reversed)); + EXPECT_EQ("ABC%20abc%20123", EncodePercent(set4, ecma262_reversed)); - EXPECT_EQ(set1, DecodePercent("%3B%2C%2F%3F%3A%40%26%3D%2B%24")); - EXPECT_EQ(set2, DecodePercent("-_.!~*'()")); - EXPECT_EQ(set3, DecodePercent("%23")); - EXPECT_EQ(set4, DecodePercent("ABC%20abc%20123")); + EXPECT_EQ(set1, DecodePercent("%3B%2C%2F%3F%3A%40%26%3D%2B%24")); + EXPECT_EQ(set2, DecodePercent("-_.!~*'()")); + EXPECT_EQ(set3, DecodePercent("%23")); + EXPECT_EQ(set4, DecodePercent("ABC%20abc%20123")); - // Reserved chars are kept. - const PercentEncodingOptions ecma262(PercentEncodingStyle::Ecma262, false); - EXPECT_EQ(";,/?:@&=+$", EncodePercent(set1, ecma262)); - EXPECT_EQ("-_.!~*'()", EncodePercent(set2, ecma262)); - EXPECT_EQ("#", EncodePercent(set3, ecma262)); - EXPECT_EQ("ABC%20abc%20123", EncodePercent(set4, ecma262)); + // Reserved chars are kept. + const PercentEncodingOptions ecma262(PercentEncodingStyle::Ecma262, false); + EXPECT_EQ(";,/?:@&=+$", EncodePercent(set1, ecma262)); + EXPECT_EQ("-_.!~*'()", EncodePercent(set2, ecma262)); + EXPECT_EQ("#", EncodePercent(set3, ecma262)); + EXPECT_EQ("ABC%20abc%20123", EncodePercent(set4, ecma262)); - EXPECT_EQ(set1, DecodePercent(";,/?:@&=+$")); - EXPECT_EQ(set2, DecodePercent("-_.!~*'()")); - EXPECT_EQ(set3, DecodePercent("#")); - EXPECT_EQ(set4, DecodePercent("ABC%20abc%20123")); + EXPECT_EQ(set1, DecodePercent(";,/?:@&=+$")); + EXPECT_EQ(set2, DecodePercent("-_.!~*'()")); + EXPECT_EQ(set3, DecodePercent("#")); + EXPECT_EQ(set4, DecodePercent("ABC%20abc%20123")); } -TEST(PercentEncoding, Rfc3986) { - Slice str = "_-,;:!?.'()[]@*/&#+=~$ABC abc 123"; +TEST(PercentEncoding, Rfc3986) +{ + Slice str = "_-,;:!?.'()[]@*/&#+=~$ABC abc 123"; - const PercentEncodingOptions rfc3986_reversed(PercentEncodingStyle::Rfc3986, - true); - const PercentEncodingOptions rfc3986(PercentEncodingStyle::Rfc3986, false); - EXPECT_EQ( - "_-%2C%3B%3A%21%3F.%27%28%29%5B%5D%40%2A%2F%26%23%2B%3D~%24ABC%20abc%" - "20123", - EncodePercent(str, rfc3986_reversed)); - EXPECT_EQ("_-,;:!?.'()[]@*/&#+=~$ABC%20abc%20123", - EncodePercent(str, rfc3986)); - EXPECT_EQ(str, - DecodePercent("_-%2C%3B%3A%21%3F.%27%28%29%5B%5D%40%2A%2F%26%23%" - "2B%3D~%24ABC%20abc%20123")); - EXPECT_EQ(str, DecodePercent("_-,;:!?.'()[]@*/&#+=~$ABC%20abc%20123")); + const PercentEncodingOptions rfc3986_reversed(PercentEncodingStyle::Rfc3986, true); + const PercentEncodingOptions rfc3986(PercentEncodingStyle::Rfc3986, false); + EXPECT_EQ("_-%2C%3B%3A%21%3F.%27%28%29%5B%5D%40%2A%2F%26%23%2B%3D~%24ABC%20abc%" + "20123", + EncodePercent(str, rfc3986_reversed)); + EXPECT_EQ("_-,;:!?.'()[]@*/&#+=~$ABC%20abc%20123", EncodePercent(str, rfc3986)); + EXPECT_EQ(str, + DecodePercent("_-%2C%3B%3A%21%3F.%27%28%29%5B%5D%40%2A%2F%26%23%" + "2B%3D~%24ABC%20abc%20123")); + EXPECT_EQ(str, DecodePercent("_-,;:!?.'()[]@*/&#+=~$ABC%20abc%20123")); } -TEST(PercentEncoding, Rfc5987) { - // `encodeRFC5987ValueChars from MDN does not seems quite right (in that it - // does escape `#` `$` ..., which is not required.): - // - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent - // - // auto encode_rfc5987_value_chars = [](Slice str) { - // auto result = - // EncodePercent(str, PercentEncodingOptions{.style = - // PercentEncodingStyle::Ecma262}); - // result = Replace(result, "'", "%" + EncodeHex("'")); - // result = Replace(result, "(", "%" + EncodeHex("(")); - // result = Replace(result, ")", "%" + EncodeHex(")")); - // result = Replace(result, "*", "%" + EncodeHex("*")); - // result = Replace(result, "%7C", "|"); - // result = Replace(result, "%60", "`"); - // result = Replace(result, "%5E", "^"); - // return result; - // }; - // - // EXPECT_EQ( - // encode_rfc5987_value_chars(str), - // EncodePercent(str, PercentEncodingOptions{.style = - // PercentEncodingStyle::Rfc5987})); +TEST(PercentEncoding, Rfc5987) +{ + // `encodeRFC5987ValueChars from MDN does not seems quite right (in that it + // does escape `#` `$` ..., which is not required.): + // + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent + // + // auto encode_rfc5987_value_chars = [](Slice str) { + // auto result = + // EncodePercent(str, PercentEncodingOptions{.style = + // PercentEncodingStyle::Ecma262}); + // result = Replace(result, "'", "%" + EncodeHex("'")); + // result = Replace(result, "(", "%" + EncodeHex("(")); + // result = Replace(result, ")", "%" + EncodeHex(")")); + // result = Replace(result, "*", "%" + EncodeHex("*")); + // result = Replace(result, "%7C", "|"); + // result = Replace(result, "%60", "`"); + // result = Replace(result, "%5E", "^"); + // return result; + // }; + // + // EXPECT_EQ( + // encode_rfc5987_value_chars(str), + // EncodePercent(str, PercentEncodingOptions{.style = + // PercentEncodingStyle::Rfc5987})); - const PercentEncodingOptions rfc5987(PercentEncodingStyle::Rfc5987, false); - const PercentEncodingOptions rfc5987_reversed(PercentEncodingStyle::Rfc5987, - true); + const PercentEncodingOptions rfc5987(PercentEncodingStyle::Rfc5987, false); + const PercentEncodingOptions rfc5987_reversed(PercentEncodingStyle::Rfc5987, true); - Slice str = "!123'-!#$&()*,./:;?@[]^_`|~+=ABC abc"; + Slice str = "!123'-!#$&()*,./:;?@[]^_`|~+=ABC abc"; - EXPECT_EQ("!123%27-!#$&%28%29%2A%2C.%2F%3A%3B%3F%40%5B%5D^_`|~+%3DABC%20abc", - EncodePercent(str, rfc5987)); - EXPECT_EQ( - str, - DecodePercent( - "!123%27-!#$&%28%29%2A%2C.%2F%3A%3B%3F%40%5B%5D^_`|~+%3DABC%20abc")); + EXPECT_EQ("!123%27-!#$&%28%29%2A%2C.%2F%3A%3B%3F%40%5B%5D^_`|~+%3DABC%20abc", EncodePercent(str, rfc5987)); + EXPECT_EQ(str, DecodePercent("!123%27-!#$&%28%29%2A%2C.%2F%3A%3B%3F%40%5B%5D^_`|~+%3DABC%20abc")); } -TEST(PercentEncoding, DecodePlusSignAsWhitespace) { - EXPECT_EQ("a+b", DecodePercent("a+b")); - EXPECT_EQ("a b", DecodePercent("a+b", true)); +TEST(PercentEncoding, DecodePlusSignAsWhitespace) +{ + EXPECT_EQ("a+b", DecodePercent("a+b")); + EXPECT_EQ("a b", DecodePercent("a+b", true)); } -} // namespace tile +}// namespace tile diff --git a/tile/base/encoding_benchmark.cc b/tile/base/encoding_benchmark.cc index e51f216..dcbd05d 100644 --- a/tile/base/encoding_benchmark.cc +++ b/tile/base/encoding_benchmark.cc @@ -7,77 +7,90 @@ namespace tile { -void Benchmark_Base64Encode(benchmark::State &state) { - std::string random_str; - std::string out; - while (state.KeepRunning()) { - state.PauseTiming(); - testing::RandomString(&random_str); - state.ResumeTiming(); +void +Benchmark_Base64Encode(benchmark::State &state) +{ + std::string random_str; + std::string out; + while (state.KeepRunning()) { + state.PauseTiming(); + testing::RandomString(&random_str); + state.ResumeTiming(); - EncodeBase64(random_str, &out); - } -} -void Benchmark_Base64Decode(benchmark::State &state) { - std::string random_str; - std::string base64; - std::string plain_text; - while (state.KeepRunning()) { - state.PauseTiming(); - testing::RandomString(&random_str); - EncodeBase64(random_str, &base64); - state.ResumeTiming(); - - DecodeBase64(base64, &plain_text); - } + EncodeBase64(random_str, &out); + } } -void Benchmark_PercentEncode(benchmark::State &state) { - std::string random_str; - std::string out; - while (state.KeepRunning()) { - state.PauseTiming(); - testing::RandomString(&random_str); - state.ResumeTiming(); - EncodeBase64(random_str, &out); - } +void +Benchmark_Base64Decode(benchmark::State &state) +{ + std::string random_str; + std::string base64; + std::string plain_text; + while (state.KeepRunning()) { + state.PauseTiming(); + testing::RandomString(&random_str); + EncodeBase64(random_str, &base64); + state.ResumeTiming(); + + DecodeBase64(base64, &plain_text); + } } -void Benchmark_PercentDecode(benchmark::State &state) { - std::string random_str; - std::string percent; - std::string plain_text; - while (state.KeepRunning()) { - state.PauseTiming(); - testing::RandomString(&random_str); - EncodePercent(random_str, &percent); - state.ResumeTiming(); - DecodePercent(percent, &plain_text); - } +void +Benchmark_PercentEncode(benchmark::State &state) +{ + std::string random_str; + std::string out; + while (state.KeepRunning()) { + state.PauseTiming(); + testing::RandomString(&random_str); + state.ResumeTiming(); + EncodeBase64(random_str, &out); + } } -void Benchmark_HexEncode(benchmark::State &state) { - std::string random_str; - std::string percent; - while (state.KeepRunning()) { - state.PauseTiming(); - testing::RandomString(&random_str); - state.ResumeTiming(); - EncodeHex(random_str, &percent); - } +void +Benchmark_PercentDecode(benchmark::State &state) +{ + std::string random_str; + std::string percent; + std::string plain_text; + while (state.KeepRunning()) { + state.PauseTiming(); + testing::RandomString(&random_str); + EncodePercent(random_str, &percent); + state.ResumeTiming(); + DecodePercent(percent, &plain_text); + } } -void Benchmark_HexDecode(benchmark::State &state) { - std::string random_str; - std::string percent; - std::string plain_text; - while (state.KeepRunning()) { - state.PauseTiming(); - testing::RandomString(&random_str); - EncodeHex(random_str, &percent); - state.ResumeTiming(); - DecodeHex(percent, &plain_text); - } +void +Benchmark_HexEncode(benchmark::State &state) +{ + std::string random_str; + std::string percent; + while (state.KeepRunning()) { + state.PauseTiming(); + testing::RandomString(&random_str); + state.ResumeTiming(); + EncodeHex(random_str, &percent); + } +} + +void +Benchmark_HexDecode(benchmark::State &state) +{ + std::string random_str; + std::string percent; + std::string plain_text; + while (state.KeepRunning()) { + state.PauseTiming(); + testing::RandomString(&random_str); + EncodeHex(random_str, &percent); + state.ResumeTiming(); + DecodeHex(percent, &plain_text); + } } BENCHMARK(Benchmark_Base64Encode); @@ -86,4 +99,4 @@ BENCHMARK(Benchmark_PercentEncode); BENCHMARK(Benchmark_PercentDecode); BENCHMARK(Benchmark_HexEncode); BENCHMARK(Benchmark_HexDecode); -} // namespace tile +}// namespace tile diff --git a/tile/base/enum.h b/tile/base/enum.h index cc8de79..c55ba51 100644 --- a/tile/base/enum.h +++ b/tile/base/enum.h @@ -6,35 +6,33 @@ #include "tile/base/internal/meta.h" namespace tile { -template ::value>> -constexpr auto underlying_value(T v) -> typename std::underlying_type::type { - return static_cast::type>(v); +template::value>> +constexpr auto +underlying_value(T v) -> typename std::underlying_type::type +{ + return static_cast::type>(v); } -#define TILE_DEFINE_ENUM_BITMASK_BINARY_OP(Type, Op) \ - constexpr Type operator Op(Type left, Type right) { \ - return static_cast(::tile::underlying_value(left) \ - Op ::tile::underlying_value(right)); \ - } -#define TILE_DEFINE_ENUM_BITMASK_UNARY_OP(Type, Op) \ - constexpr Type operator Op(Type v) { \ - return static_cast(Op ::tile::underlying_value(v)); \ - } -#define TILE_DEFINE_ENUM_BITMASK_BINARY_ASSIGN_OP(Type, Op) \ - constexpr Type &operator Op(Type & left, Type right) { return left Op right; } +#define TILE_DEFINE_ENUM_BITMASK_BINARY_OP(Type, Op) \ + constexpr Type operator Op(Type left, Type right) \ + { \ + return static_cast(::tile::underlying_value(left) Op ::tile::underlying_value(right)); \ + } +#define TILE_DEFINE_ENUM_BITMASK_UNARY_OP(Type, Op) \ + constexpr Type operator Op(Type v) { return static_cast(Op ::tile::underlying_value(v)); } +#define TILE_DEFINE_ENUM_BITMASK_BINARY_ASSIGN_OP(Type, Op) \ + constexpr Type &operator Op(Type & left, Type right) { return left Op right; } -#define TILE_DEFINE_ENUM_BITMASK_OPS(Type) \ - TILE_DEFINE_ENUM_BITMASK_BINARY_OP(Type, |) \ - TILE_DEFINE_ENUM_BITMASK_BINARY_OP(Type, &) \ - TILE_DEFINE_ENUM_BITMASK_BINARY_OP(Type, ^) \ - TILE_DEFINE_ENUM_BITMASK_BINARY_ASSIGN_OP(Type, |=) \ - TILE_DEFINE_ENUM_BITMASK_BINARY_ASSIGN_OP(Type, &=) \ - TILE_DEFINE_ENUM_BITMASK_BINARY_ASSIGN_OP(Type, ^=) \ - TILE_DEFINE_ENUM_BITMASK_UNARY_OP(Type, ~) \ - constexpr bool operator!(Type value) { \ - return !::tile::underlying_value(value); \ - } +#define TILE_DEFINE_ENUM_BITMASK_OPS(Type) \ + TILE_DEFINE_ENUM_BITMASK_BINARY_OP(Type, |) \ + TILE_DEFINE_ENUM_BITMASK_BINARY_OP(Type, &) \ + TILE_DEFINE_ENUM_BITMASK_BINARY_OP(Type, ^) \ + TILE_DEFINE_ENUM_BITMASK_BINARY_ASSIGN_OP(Type, |=) \ + TILE_DEFINE_ENUM_BITMASK_BINARY_ASSIGN_OP(Type, &=) \ + TILE_DEFINE_ENUM_BITMASK_BINARY_ASSIGN_OP(Type, ^=) \ + TILE_DEFINE_ENUM_BITMASK_UNARY_OP(Type, ~) \ + constexpr bool operator!(Type value) { return !::tile::underlying_value(value); } -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_ENUM_H +#endif// _TILE_BASE_ENUM_H diff --git a/tile/base/erased_ptr.h b/tile/base/erased_ptr.h index 878fd28..49cea40 100644 --- a/tile/base/erased_ptr.h +++ b/tile/base/erased_ptr.h @@ -12,58 +12,69 @@ namespace tile { // RAII wrapper ptr class ErasedPtr final { public: - using Deleter = void (*)(void *); - constexpr ErasedPtr(std::nullptr_t = nullptr) - : ptr_(nullptr), deleter_(nullptr) {} - template - constexpr ErasedPtr(T *ptr) noexcept - : ptr_(ptr), deleter_([](void *ptr) { delete static_cast(ptr); }) {} - template - constexpr ErasedPtr(T *ptr, D deleter) noexcept - : ptr_(ptr), deleter_(deleter) {} - ErasedPtr(ErasedPtr &&ptr) noexcept : ptr_(ptr.ptr_), deleter_(ptr.deleter_) { - ptr.ptr_ = nullptr; - } + using Deleter = void (*)(void *); - ErasedPtr &operator=(ErasedPtr &&ptr) noexcept { - if (TILE_LIKELY(this != &ptr)) { - Reset(); + constexpr ErasedPtr(std::nullptr_t = nullptr) : ptr_(nullptr), deleter_(nullptr) {} + + template + constexpr ErasedPtr(T *ptr) noexcept + : ptr_(ptr), + deleter_([](void *ptr) { delete static_cast(ptr); }) + {} + + template + constexpr ErasedPtr(T *ptr, D deleter) noexcept + : ptr_(ptr), + deleter_(deleter) + {} + + ErasedPtr(ErasedPtr &&ptr) noexcept : ptr_(ptr.ptr_), deleter_(ptr.deleter_) { ptr.ptr_ = nullptr; } + + ErasedPtr &operator=(ErasedPtr &&ptr) noexcept + { + if (TILE_LIKELY(this != &ptr)) { Reset(); } + return *this; } - return *this; - } - ErasedPtr(const ErasedPtr &) = delete; - ErasedPtr &operator=(const ErasedPtr &) = delete; + ErasedPtr(const ErasedPtr &) = delete; + ErasedPtr &operator=(const ErasedPtr &) = delete; - ~ErasedPtr() { - if (ptr_) { - deleter_(ptr_); + ~ErasedPtr() + { + if (ptr_) { deleter_(ptr_); } } - } - constexpr void *Get() const noexcept { return ptr_; } - template T *UncheckedGet() const noexcept { - return static_cast(ptr_); - } - constexpr explicit operator bool() const noexcept { return !!ptr_; } - void Reset(std::nullptr_t = nullptr) noexcept { - if (ptr_) { - deleter_(ptr_); - ptr_ = nullptr; + constexpr void *Get() const noexcept { return ptr_; } + + template + T *UncheckedGet() const noexcept + { + return static_cast(ptr_); } - } - TILE_NODISCARD void *Leak() noexcept { - void *rc = nullptr; - std::swap(rc, ptr_); - return rc; - } - constexpr Deleter GetDeleter() const noexcept { return deleter_; } + constexpr explicit operator bool() const noexcept { return !!ptr_; } + + void Reset(std::nullptr_t = nullptr) noexcept + { + if (ptr_) { + deleter_(ptr_); + ptr_ = nullptr; + } + } + + TILE_NODISCARD void *Leak() noexcept + { + void *rc = nullptr; + std::swap(rc, ptr_); + return rc; + } + + constexpr Deleter GetDeleter() const noexcept { return deleter_; } private: - void *ptr_; - Deleter deleter_; + void *ptr_; + Deleter deleter_; }; -} // namespace tile +}// namespace tile -#endif // _TILE_BASE_ERASED_PTR_H +#endif// _TILE_BASE_ERASED_PTR_H diff --git a/tile/base/expected.h b/tile/base/expected.h index c7057f4..eae217c 100644 --- a/tile/base/expected.h +++ b/tile/base/expected.h @@ -17,9 +17,9 @@ #define expected_lite_MINOR 6 #define expected_lite_PATCH 3 -#define expected_lite_VERSION \ - expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY( \ - expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH) +#define expected_lite_VERSION \ + expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY( \ + expected_lite_PATCH) #define expected_STRINGIFY(x) expected_STRINGIFY_(x) #define expected_STRINGIFY_(x) #x @@ -45,8 +45,7 @@ // expected selection and configuration: #if !defined(nsel_CONFIG_SELECT_EXPECTED) -#define nsel_CONFIG_SELECT_EXPECTED \ - (nsel_HAVE_STD_EXPECTED ? nsel_EXPECTED_STD : nsel_EXPECTED_NONSTD) +#define nsel_CONFIG_SELECT_EXPECTED (nsel_HAVE_STD_EXPECTED ? nsel_EXPECTED_STD : nsel_EXPECTED_NONSTD) #endif // Proposal revisions: @@ -89,7 +88,7 @@ #ifndef nsel_CONFIG_NO_EXCEPTIONS #if defined(_MSC_VER) -#include // for _HAS_EXCEPTIONS +#include // for _HAS_EXCEPTIONS #endif #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) #define nsel_CONFIG_NO_EXCEPTIONS 0 @@ -134,10 +133,9 @@ #define nsel_HAVE_STD_EXPECTED 0 #endif -#define nsel_USES_STD_EXPECTED \ - ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) || \ - ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && \ - nsel_HAVE_STD_EXPECTED)) +#define nsel_USES_STD_EXPECTED \ + ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) \ + || ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && nsel_HAVE_STD_EXPECTED)) // // in_place: code duplicated in any-lite, expected-lite, expected-lite, @@ -166,71 +164,74 @@ using std::in_place_type_t; #define nonstd_lite_in_place_type_t(T) std::in_place_type_t #define nonstd_lite_in_place_index_t(K) std::in_place_index_t -#define nonstd_lite_in_place(T) \ - std::in_place_t {} -#define nonstd_lite_in_place_type(T) \ - std::in_place_type_t {} -#define nonstd_lite_in_place_index(K) \ - std::in_place_index_t {} +#define nonstd_lite_in_place(T) \ + std::in_place_t {} +#define nonstd_lite_in_place_type(T) \ + std::in_place_type_t {} +#define nonstd_lite_in_place_index(K) \ + std::in_place_index_t {} -} // namespace nonstd +}// namespace nonstd -#else // nsel_CPP17_OR_GREATER +#else// nsel_CPP17_OR_GREATER #include namespace nonstd { namespace detail { -template struct in_place_type_tag {}; +template +struct in_place_type_tag {}; -template struct in_place_index_tag {}; +template +struct in_place_index_tag {}; -} // namespace detail +}// namespace detail struct in_place_t {}; -template +template inline in_place_t -in_place(detail::in_place_type_tag = detail::in_place_type_tag()) { - return in_place_t(); +in_place(detail::in_place_type_tag = detail::in_place_type_tag()) +{ + return in_place_t(); } -template +template inline in_place_t -in_place(detail::in_place_index_tag = detail::in_place_index_tag()) { - return in_place_t(); +in_place(detail::in_place_index_tag = detail::in_place_index_tag()) +{ + return in_place_t(); } -template +template inline in_place_t -in_place_type(detail::in_place_type_tag = detail::in_place_type_tag()) { - return in_place_t(); +in_place_type(detail::in_place_type_tag = detail::in_place_type_tag()) +{ + return in_place_t(); } -template -inline in_place_t in_place_index( - detail::in_place_index_tag = detail::in_place_index_tag()) { - return in_place_t(); +template +inline in_place_t +in_place_index(detail::in_place_index_tag = detail::in_place_index_tag()) +{ + return in_place_t(); } // mimic templated typedef: -#define nonstd_lite_in_place_t(T) \ - nonstd::in_place_t (&)(nonstd::detail::in_place_type_tag) -#define nonstd_lite_in_place_type_t(T) \ - nonstd::in_place_t (&)(nonstd::detail::in_place_type_tag) -#define nonstd_lite_in_place_index_t(K) \ - nonstd::in_place_t (&)(nonstd::detail::in_place_index_tag) +#define nonstd_lite_in_place_t(T) nonstd::in_place_t (&)(nonstd::detail::in_place_type_tag) +#define nonstd_lite_in_place_type_t(T) nonstd::in_place_t (&)(nonstd::detail::in_place_type_tag) +#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t (&)(nonstd::detail::in_place_index_tag) #define nonstd_lite_in_place(T) nonstd::in_place_type #define nonstd_lite_in_place_type(T) nonstd::in_place_type #define nonstd_lite_in_place_index(K) nonstd::in_place_index -} // namespace nonstd +}// namespace nonstd -#endif // nsel_CPP17_OR_GREATER -#endif // nonstd_lite_HAVE_IN_PLACE_TYPES +#endif// nsel_CPP17_OR_GREATER +#endif// nonstd_lite_HAVE_IN_PLACE_TYPES // // Using std::expected: @@ -244,9 +245,9 @@ namespace nonstd { using std::expected; // ... -} // namespace nonstd +}// namespace nonstd -#else // nsel_USES_STD_EXPECTED +#else// nsel_USES_STD_EXPECTED #include #include @@ -262,7 +263,7 @@ using std::expected; #if nsel_CONFIG_NO_EXCEPTIONS #if nsel_CONFIG_NO_EXCEPTIONS_SEH -#include // for ExceptionCodes +#include // for ExceptionCodes #else // already included: #endif @@ -309,26 +310,22 @@ using std::expected; #if defined(_MSC_VER) && !defined(__clang__) #define nsel_COMPILER_MSVC_VER (_MSC_VER) -#define nsel_COMPILER_MSVC_VERSION \ - (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900))) +#define nsel_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900))) #else #define nsel_COMPILER_MSVC_VER 0 #define nsel_COMPILER_MSVC_VERSION 0 #endif -#define nsel_COMPILER_VERSION(major, minor, patch) \ - (10 * (10 * (major) + (minor)) + (patch)) +#define nsel_COMPILER_VERSION(major, minor, patch) (10 * (10 * (major) + (minor)) + (patch)) #if defined(__clang__) -#define nsel_COMPILER_CLANG_VERSION \ - nsel_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#define nsel_COMPILER_CLANG_VERSION nsel_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) #else #define nsel_COMPILER_CLANG_VERSION 0 #endif #if defined(__GNUC__) && !defined(__clang__) -#define nsel_COMPILER_GNUC_VERSION \ - nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#define nsel_COMPILER_GNUC_VERSION nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #else #define nsel_COMPILER_GNUC_VERSION 0 #endif @@ -338,16 +335,13 @@ using std::expected; // Method enabling -#define nsel_REQUIRES_0(...) \ - template ::type = 0> +#define nsel_REQUIRES_0(...) template::type = 0> -#define nsel_REQUIRES_T(...) \ - , typename std::enable_if<(__VA_ARGS__), int>::type = 0 +#define nsel_REQUIRES_T(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0 #define nsel_REQUIRES_R(R, ...) typename std::enable_if<(__VA_ARGS__), R>::type -#define nsel_REQUIRES_A(...) \ - , typename std::enable_if<(__VA_ARGS__), void *>::type = nullptr +#define nsel_REQUIRES_A(...) , typename std::enable_if<(__VA_ARGS__), void *>::type = nullptr // Presence of language and library features: @@ -366,7 +360,7 @@ using std::expected; #pragma clang diagnostic push #elif defined __GNUC__ #pragma GCC diagnostic push -#endif // __clang__ +#endif// __clang__ #if nsel_COMPILER_MSVC_VERSION >= 140 #pragma warning(push) @@ -395,2643 +389,2478 @@ nsel_DISABLE_MSVC_WARNINGS(26409) // expected: // - namespace nonstd { - namespace expected_lite { + namespace nonstd +{ + namespace expected_lite { - // type traits C++17: + // type traits C++17: - namespace std17 { + namespace std17 { #if nsel_CPP17_OR_GREATER - using std::conjunction; - using std::is_nothrow_swappable; - using std::is_swappable; + using std::conjunction; + using std::is_nothrow_swappable; + using std::is_swappable; -#else // nsel_CPP17_OR_GREATER +#else// nsel_CPP17_OR_GREATER - namespace detail { + namespace detail { - using std::swap; + using std::swap; - struct is_swappable { - template (), - std::declval()))> - static std::true_type test(int /* unused */); + struct is_swappable { + template(), std::declval()))> + static std::true_type test(int /* unused */); - template static std::false_type test(...); - }; + template + static std::false_type test(...); + }; - struct is_nothrow_swappable { - // wrap noexcept(expr) in separate function as work-around for VC140 - // (VS2015): + struct is_nothrow_swappable { + // wrap noexcept(expr) in separate function as work-around for VC140 + // (VS2015): - template static constexpr bool satisfies() { - return noexcept(swap(std::declval(), std::declval())); - } + template + static constexpr bool satisfies() + { + return noexcept(swap(std::declval(), std::declval())); + } - template - static auto test(int) -> std::integral_constant()> {} + template + static auto test(int) -> std::integral_constant()> + {} - template static auto test(...) -> std::false_type; - }; - } // namespace detail + template + static auto test(...) -> std::false_type; + }; + }// namespace detail - // is [nothrow] swappable: + // is [nothrow] swappable: - template - struct is_swappable : decltype(detail::is_swappable::test(0)) {}; + template + struct is_swappable : decltype(detail::is_swappable::test(0)) {}; - template - struct is_nothrow_swappable - : decltype(detail::is_nothrow_swappable::test(0)) {}; + template + struct is_nothrow_swappable : decltype(detail::is_nothrow_swappable::test(0)) {}; - // conjunction: + // conjunction: - template struct conjunction : std::true_type {}; - template struct conjunction : B1 {}; + template + struct conjunction : std::true_type {}; - template - struct conjunction - : std::conditional, B1>::type {}; + template + struct conjunction : B1 {}; -#endif // nsel_CPP17_OR_GREATER + template + struct conjunction : std::conditional, B1>::type {}; - } // namespace std17 +#endif// nsel_CPP17_OR_GREATER - // type traits C++20: + }// namespace std17 - namespace std20 { + // type traits C++20: + + namespace std20 { #if defined(__cpp_lib_remove_cvref) - using std::remove_cvref; + using std::remove_cvref; #else - template struct remove_cvref { - typedef - typename std::remove_cv::type>::type - type; - }; + template + struct remove_cvref { + typedef typename std::remove_cv::type>::type type; + }; #endif - } // namespace std20 + }// namespace std20 - // forward declaration: + // forward declaration: - template class expected; + template + class expected; - namespace detail { + namespace detail { #if nsel_P2505R >= 3 - template struct is_expected : std::false_type {}; + template + struct is_expected : std::false_type {}; - template - struct is_expected> : std::true_type {}; -#endif // nsel_P2505R >= 3 + template + struct is_expected> : std::true_type {}; +#endif// nsel_P2505R >= 3 - /// discriminated union to hold value or 'error'. + /// discriminated union to hold value or 'error'. - template class storage_t_noncopy_nonmove_impl { - template friend class nonstd::expected_lite::expected; + template + class storage_t_noncopy_nonmove_impl { + template + friend class nonstd::expected_lite::expected; - public: - using value_type = T; - using error_type = E; + public: + using value_type = T; + using error_type = E; - // no-op construction - storage_t_noncopy_nonmove_impl() {} - ~storage_t_noncopy_nonmove_impl() {} + // no-op construction + storage_t_noncopy_nonmove_impl() {} - explicit storage_t_noncopy_nonmove_impl(bool has_value) - : m_has_value(has_value) {} + ~storage_t_noncopy_nonmove_impl() {} - void construct_value() { new (&m_value) value_type(); } + explicit storage_t_noncopy_nonmove_impl(bool has_value) : m_has_value(has_value) {} - // void construct_value( value_type const & e ) - // { - // new( &m_value ) value_type( e ); - // } + void construct_value() { new (&m_value) value_type(); } - // void construct_value( value_type && e ) - // { - // new( &m_value ) value_type( std::move( e ) ); - // } + // void construct_value( value_type const & e ) + // { + // new( &m_value ) value_type( e ); + // } - template void emplace_value(Args &&...args) { - new (&m_value) value_type(std::forward(args)...); - } + // void construct_value( value_type && e ) + // { + // new( &m_value ) value_type( std::move( e ) ); + // } - template - void emplace_value(std::initializer_list il, Args &&...args) { - new (&m_value) value_type(il, std::forward(args)...); - } + template + void emplace_value(Args &&...args) + { + new (&m_value) value_type(std::forward(args)...); + } - void destruct_value() { m_value.~value_type(); } + template + void emplace_value(std::initializer_list il, Args &&...args) + { + new (&m_value) value_type(il, std::forward(args)...); + } - // void construct_error( error_type const & e ) - // { - // // new( &m_error ) error_type( e ); - // } + void destruct_value() { m_value.~value_type(); } - // void construct_error( error_type && e ) - // { - // // new( &m_error ) error_type( std::move( e ) ); - // } + // void construct_error( error_type const & e ) + // { + // // new( &m_error ) error_type( e ); + // } - template void emplace_error(Args &&...args) { - new (&m_error) error_type(std::forward(args)...); - } + // void construct_error( error_type && e ) + // { + // // new( &m_error ) error_type( std::move( e ) ); + // } - template - void emplace_error(std::initializer_list il, Args &&...args) { - new (&m_error) error_type(il, std::forward(args)...); - } + template + void emplace_error(Args &&...args) + { + new (&m_error) error_type(std::forward(args)...); + } - void destruct_error() { m_error.~error_type(); } + template + void emplace_error(std::initializer_list il, Args &&...args) + { + new (&m_error) error_type(il, std::forward(args)...); + } - constexpr value_type const &value() const & { return m_value; } + void destruct_error() { m_error.~error_type(); } - value_type &value() & { return m_value; } + constexpr value_type const &value() const & { return m_value; } - constexpr value_type const &&value() const && { return std::move(m_value); } + value_type &value() & { return m_value; } - nsel_constexpr14 value_type &&value() && { return std::move(m_value); } + constexpr value_type const &&value() const && { return std::move(m_value); } - value_type const *value_ptr() const { return &m_value; } + nsel_constexpr14 value_type &&value() && { return std::move(m_value); } - value_type *value_ptr() { return &m_value; } + value_type const *value_ptr() const { return &m_value; } - error_type const &error() const & { return m_error; } + value_type *value_ptr() { return &m_value; } - error_type &error() & { return m_error; } + error_type const &error() const & { return m_error; } - constexpr error_type const &&error() const && { return std::move(m_error); } + error_type &error() & { return m_error; } - nsel_constexpr14 error_type &&error() && { return std::move(m_error); } + constexpr error_type const &&error() const && { return std::move(m_error); } - bool has_value() const { return m_has_value; } + nsel_constexpr14 error_type &&error() && { return std::move(m_error); } - void set_has_value(bool v) { m_has_value = v; } + bool has_value() const { return m_has_value; } - private: - union { - value_type m_value; - error_type m_error; + void set_has_value(bool v) { m_has_value = v; } + + private: + union { + value_type m_value; + error_type m_error; + }; + + bool m_has_value = false; }; - bool m_has_value = false; - }; + template + class storage_t_impl { + template + friend class nonstd::expected_lite::expected; - template class storage_t_impl { - template friend class nonstd::expected_lite::expected; + public: + using value_type = T; + using error_type = E; - public: - using value_type = T; - using error_type = E; + // no-op construction + storage_t_impl() {} - // no-op construction - storage_t_impl() {} - ~storage_t_impl() {} + ~storage_t_impl() {} - explicit storage_t_impl(bool has_value) : m_has_value(has_value) {} + explicit storage_t_impl(bool has_value) : m_has_value(has_value) {} - void construct_value() { new (&m_value) value_type(); } + void construct_value() { new (&m_value) value_type(); } - void construct_value(value_type const &e) { new (&m_value) value_type(e); } + void construct_value(value_type const &e) { new (&m_value) value_type(e); } - void construct_value(value_type &&e) { - new (&m_value) value_type(std::move(e)); - } + void construct_value(value_type &&e) { new (&m_value) value_type(std::move(e)); } - template void emplace_value(Args &&...args) { - new (&m_value) value_type(std::forward(args)...); - } + template + void emplace_value(Args &&...args) + { + new (&m_value) value_type(std::forward(args)...); + } - template - void emplace_value(std::initializer_list il, Args &&...args) { - new (&m_value) value_type(il, std::forward(args)...); - } + template + void emplace_value(std::initializer_list il, Args &&...args) + { + new (&m_value) value_type(il, std::forward(args)...); + } - void destruct_value() { m_value.~value_type(); } + void destruct_value() { m_value.~value_type(); } - void construct_error(error_type const &e) { new (&m_error) error_type(e); } + void construct_error(error_type const &e) { new (&m_error) error_type(e); } - void construct_error(error_type &&e) { - new (&m_error) error_type(std::move(e)); - } + void construct_error(error_type &&e) { new (&m_error) error_type(std::move(e)); } - template void emplace_error(Args &&...args) { - new (&m_error) error_type(std::forward(args)...); - } + template + void emplace_error(Args &&...args) + { + new (&m_error) error_type(std::forward(args)...); + } - template - void emplace_error(std::initializer_list il, Args &&...args) { - new (&m_error) error_type(il, std::forward(args)...); - } + template + void emplace_error(std::initializer_list il, Args &&...args) + { + new (&m_error) error_type(il, std::forward(args)...); + } - void destruct_error() { m_error.~error_type(); } + void destruct_error() { m_error.~error_type(); } - constexpr value_type const &value() const & { return m_value; } + constexpr value_type const &value() const & { return m_value; } - value_type &value() & { return m_value; } + value_type &value() & { return m_value; } - constexpr value_type const &&value() const && { return std::move(m_value); } + constexpr value_type const &&value() const && { return std::move(m_value); } - nsel_constexpr14 value_type &&value() && { return std::move(m_value); } + nsel_constexpr14 value_type &&value() && { return std::move(m_value); } - value_type const *value_ptr() const { return &m_value; } + value_type const *value_ptr() const { return &m_value; } - value_type *value_ptr() { return &m_value; } + value_type *value_ptr() { return &m_value; } - error_type const &error() const & { return m_error; } + error_type const &error() const & { return m_error; } - error_type &error() & { return m_error; } + error_type &error() & { return m_error; } - constexpr error_type const &&error() const && { return std::move(m_error); } + constexpr error_type const &&error() const && { return std::move(m_error); } - nsel_constexpr14 error_type &&error() && { return std::move(m_error); } + nsel_constexpr14 error_type &&error() && { return std::move(m_error); } - bool has_value() const { return m_has_value; } + bool has_value() const { return m_has_value; } - void set_has_value(bool v) { m_has_value = v; } + void set_has_value(bool v) { m_has_value = v; } - private: - union { - value_type m_value; - error_type m_error; + private: + union { + value_type m_value; + error_type m_error; + }; + + bool m_has_value = false; }; - bool m_has_value = false; - }; + /// discriminated union to hold only 'error'. - /// discriminated union to hold only 'error'. + template + struct storage_t_impl { + template + friend class nonstd::expected_lite::expected; - template struct storage_t_impl { - template friend class nonstd::expected_lite::expected; + public: + using value_type = void; + using error_type = E; - public: - using value_type = void; - using error_type = E; + // no-op construction + storage_t_impl() {} - // no-op construction - storage_t_impl() {} - ~storage_t_impl() {} + ~storage_t_impl() {} - explicit storage_t_impl(bool has_value) : m_has_value(has_value) {} + explicit storage_t_impl(bool has_value) : m_has_value(has_value) {} - void construct_error(error_type const &e) { new (&m_error) error_type(e); } + void construct_error(error_type const &e) { new (&m_error) error_type(e); } - void construct_error(error_type &&e) { - new (&m_error) error_type(std::move(e)); - } + void construct_error(error_type &&e) { new (&m_error) error_type(std::move(e)); } - template void emplace_error(Args &&...args) { - new (&m_error) error_type(std::forward(args)...); - } + template + void emplace_error(Args &&...args) + { + new (&m_error) error_type(std::forward(args)...); + } - template - void emplace_error(std::initializer_list il, Args &&...args) { - new (&m_error) error_type(il, std::forward(args)...); - } + template + void emplace_error(std::initializer_list il, Args &&...args) + { + new (&m_error) error_type(il, std::forward(args)...); + } - void destruct_error() { m_error.~error_type(); } + void destruct_error() { m_error.~error_type(); } - error_type const &error() const & { return m_error; } + error_type const &error() const & { return m_error; } - error_type &error() & { return m_error; } + error_type &error() & { return m_error; } - constexpr error_type const &&error() const && { return std::move(m_error); } + constexpr error_type const &&error() const && { return std::move(m_error); } - nsel_constexpr14 error_type &&error() && { return std::move(m_error); } + nsel_constexpr14 error_type &&error() && { return std::move(m_error); } - bool has_value() const { return m_has_value; } + bool has_value() const { return m_has_value; } - void set_has_value(bool v) { m_has_value = v; } + void set_has_value(bool v) { m_has_value = v; } - private: - union { - char m_dummy; - error_type m_error; + private: + union { + char m_dummy; + error_type m_error; + }; + + bool m_has_value = false; }; - bool m_has_value = false; - }; + template + class storage_t { + public: + }; - template - class storage_t { - public: - }; + template + class storage_t : public storage_t_noncopy_nonmove_impl { + public: + storage_t() = default; + ~storage_t() = default; - template - class storage_t - : public storage_t_noncopy_nonmove_impl { - public: - storage_t() = default; - ~storage_t() = default; + explicit storage_t(bool has_value) : storage_t_noncopy_nonmove_impl(has_value) {} - explicit storage_t(bool has_value) - : storage_t_noncopy_nonmove_impl(has_value) {} + storage_t(storage_t const &other) = delete; + storage_t(storage_t &&other) = delete; + }; - storage_t(storage_t const &other) = delete; - storage_t(storage_t &&other) = delete; - }; + template + class storage_t : public storage_t_impl { + public: + storage_t() = default; + ~storage_t() = default; - template - class storage_t : public storage_t_impl { - public: - storage_t() = default; - ~storage_t() = default; + explicit storage_t(bool has_value) : storage_t_impl(has_value) {} - explicit storage_t(bool has_value) : storage_t_impl(has_value) {} + storage_t(storage_t const &other) : storage_t_impl(other.has_value()) + { + if (this->has_value()) + this->construct_value(other.value()); + else + this->construct_error(other.error()); + } - storage_t(storage_t const &other) - : storage_t_impl(other.has_value()) { - if (this->has_value()) - this->construct_value(other.value()); - else - this->construct_error(other.error()); - } + storage_t(storage_t &&other) : storage_t_impl(other.has_value()) + { + if (this->has_value()) + this->construct_value(std::move(other.value())); + else + this->construct_error(std::move(other.error())); + } + }; - storage_t(storage_t &&other) : storage_t_impl(other.has_value()) { - if (this->has_value()) - this->construct_value(std::move(other.value())); - else - this->construct_error(std::move(other.error())); - } - }; + template + class storage_t : public storage_t_impl { + public: + storage_t() = default; + ~storage_t() = default; - template - class storage_t : public storage_t_impl { - public: - storage_t() = default; - ~storage_t() = default; + explicit storage_t(bool has_value) : storage_t_impl(has_value) {} - explicit storage_t(bool has_value) : storage_t_impl(has_value) {} + storage_t(storage_t const &other) : storage_t_impl(other.has_value()) + { + if (this->has_value()) + ; + else + this->construct_error(other.error()); + } - storage_t(storage_t const &other) - : storage_t_impl(other.has_value()) { - if (this->has_value()) - ; - else - this->construct_error(other.error()); - } + storage_t(storage_t &&other) : storage_t_impl(other.has_value()) + { + if (this->has_value()) + ; + else + this->construct_error(std::move(other.error())); + } + }; - storage_t(storage_t &&other) : storage_t_impl(other.has_value()) { - if (this->has_value()) - ; - else - this->construct_error(std::move(other.error())); - } - }; + template + class storage_t : public storage_t_impl { + public: + storage_t() = default; + ~storage_t() = default; - template - class storage_t : public storage_t_impl { - public: - storage_t() = default; - ~storage_t() = default; + explicit storage_t(bool has_value) : storage_t_impl(has_value) {} - explicit storage_t(bool has_value) : storage_t_impl(has_value) {} + storage_t(storage_t const &other) : storage_t_impl(other.has_value()) + { + if (this->has_value()) + this->construct_value(other.value()); + else + this->construct_error(other.error()); + } - storage_t(storage_t const &other) - : storage_t_impl(other.has_value()) { - if (this->has_value()) - this->construct_value(other.value()); - else - this->construct_error(other.error()); - } + storage_t(storage_t &&other) = delete; + }; - storage_t(storage_t &&other) = delete; - }; + template + class storage_t : public storage_t_impl { + public: + storage_t() = default; + ~storage_t() = default; - template - class storage_t : public storage_t_impl { - public: - storage_t() = default; - ~storage_t() = default; + explicit storage_t(bool has_value) : storage_t_impl(has_value) {} - explicit storage_t(bool has_value) : storage_t_impl(has_value) {} + storage_t(storage_t const &other) : storage_t_impl(other.has_value()) + { + if (this->has_value()) + ; + else + this->construct_error(other.error()); + } - storage_t(storage_t const &other) - : storage_t_impl(other.has_value()) { - if (this->has_value()) - ; - else - this->construct_error(other.error()); - } + storage_t(storage_t &&other) = delete; + }; - storage_t(storage_t &&other) = delete; - }; + template + class storage_t : public storage_t_impl { + public: + storage_t() = default; + ~storage_t() = default; - template - class storage_t : public storage_t_impl { - public: - storage_t() = default; - ~storage_t() = default; + explicit storage_t(bool has_value) : storage_t_impl(has_value) {} - explicit storage_t(bool has_value) : storage_t_impl(has_value) {} + storage_t(storage_t const &other) = delete; - storage_t(storage_t const &other) = delete; + storage_t(storage_t &&other) : storage_t_impl(other.has_value()) + { + if (this->has_value()) + this->construct_value(std::move(other.value())); + else + this->construct_error(std::move(other.error())); + } + }; - storage_t(storage_t &&other) : storage_t_impl(other.has_value()) { - if (this->has_value()) - this->construct_value(std::move(other.value())); - else - this->construct_error(std::move(other.error())); - } - }; + template + class storage_t : public storage_t_impl { + public: + storage_t() = default; + ~storage_t() = default; - template - class storage_t : public storage_t_impl { - public: - storage_t() = default; - ~storage_t() = default; + explicit storage_t(bool has_value) : storage_t_impl(has_value) {} - explicit storage_t(bool has_value) : storage_t_impl(has_value) {} + storage_t(storage_t const &other) = delete; - storage_t(storage_t const &other) = delete; - - storage_t(storage_t &&other) : storage_t_impl(other.has_value()) { - if (this->has_value()) - ; - else - this->construct_error(std::move(other.error())); - } - }; + storage_t(storage_t &&other) : storage_t_impl(other.has_value()) + { + if (this->has_value()) + ; + else + this->construct_error(std::move(other.error())); + } + }; #if nsel_P2505R >= 3 - // C++11 invoke implementation - template struct is_reference_wrapper : std::false_type {}; - template - struct is_reference_wrapper> : std::true_type {}; + // C++11 invoke implementation + template + struct is_reference_wrapper : std::false_type {}; - template < - typename FnT, typename ClassT, typename ObjectT, - typename... Args nsel_REQUIRES_T( - std::is_function::value && - (std::is_same::type>::value || - std::is_base_of< - ClassT, typename std20::remove_cvref::type>::value))> - nsel_constexpr auto invoke_member_function_impl( - FnT ClassT::*memfnptr, ObjectT &&obj, - Args &&...args) noexcept(noexcept((std::forward(obj).* - memfnptr)(std::forward( - args)...))) -> decltype((std::forward(obj).* - memfnptr)(std::forward(args)...)) { - return (std::forward(obj).*memfnptr)(std::forward(args)...); - } + template + struct is_reference_wrapper> : std::true_type {}; - template ::value &&is_reference_wrapper< - typename std20::remove_cvref::type>::value)> - nsel_constexpr auto - invoke_member_function_impl(FnT ClassT::*memfnptr, ObjectT &&obj, - Args &&...args) noexcept(noexcept((obj.get().* - memfnptr)( - std::forward(args)...))) - -> decltype((obj.get().*memfnptr)(std::forward(args)...)) { - return (obj.get().*memfnptr)(std::forward(args)...); - } + template::value + && (std::is_same::type>::value + || std::is_base_of::type>::value))> + nsel_constexpr auto invoke_member_function_impl(FnT ClassT::*memfnptr, ObjectT &&obj, Args &&...args) noexcept( + noexcept((std::forward(obj).*memfnptr)(std::forward(args)...))) + -> decltype((std::forward(obj).*memfnptr)(std::forward(args)...)) + { + return (std::forward(obj).*memfnptr)(std::forward(args)...); + } - template < - typename FnT, typename ClassT, typename ObjectT, - typename... Args nsel_REQUIRES_T( - std::is_function::value && - !std::is_same::type>::value && - !std::is_base_of< - ClassT, typename std20::remove_cvref::type>::value && - !is_reference_wrapper< - typename std20::remove_cvref::type>::value)> - nsel_constexpr auto invoke_member_function_impl( - FnT ClassT::*memfnptr, ObjectT &&obj, - Args &&...args) noexcept(noexcept(((*std::forward(obj)).* - memfnptr)(std::forward( - args)...))) -> decltype(((*std::forward(obj)).* - memfnptr)(std::forward(args)...)) { - return ((*std::forward(obj)).* - memfnptr)(std::forward(args)...); - } + template::value &&is_reference_wrapper< + typename std20::remove_cvref::type>::value)> + nsel_constexpr auto invoke_member_function_impl(FnT ClassT::*memfnptr, ObjectT &&obj, Args &&...args) noexcept( + noexcept((obj.get().*memfnptr)(std::forward(args)...))) + -> decltype((obj.get().*memfnptr)(std::forward(args)...)) + { + return (obj.get().*memfnptr)(std::forward(args)...); + } - template < - typename MemberT, typename ClassT, - typename ObjectT nsel_REQUIRES_T( - std::is_same::type>::value || - std::is_base_of::type>::value)> - nsel_constexpr auto - invoke_member_object_impl(MemberT ClassT::*memobjptr, ObjectT &&obj) noexcept( - noexcept(std::forward(obj).* - memobjptr)) -> decltype(std::forward(obj).*memobjptr) { - return std::forward(obj).*memobjptr; - } + template::value + && !std::is_same::type>::value + && !std::is_base_of::type>::value + && !is_reference_wrapper::type>::value)> + nsel_constexpr auto invoke_member_function_impl(FnT ClassT::*memfnptr, ObjectT &&obj, Args &&...args) noexcept( + noexcept(((*std::forward(obj)).*memfnptr)(std::forward(args)...))) + -> decltype(((*std::forward(obj)).*memfnptr)(std::forward(args)...)) + { + return ((*std::forward(obj)).*memfnptr)(std::forward(args)...); + } - template ::type>::value)> - nsel_constexpr auto - invoke_member_object_impl(MemberT ClassT::*memobjptr, ObjectT &&obj) noexcept( - noexcept(obj.get().*memobjptr)) -> decltype(obj.get().*memobjptr) { - return obj.get().*memobjptr; - } + template::type>::value + || std::is_base_of::type>::value)> + nsel_constexpr auto invoke_member_object_impl(MemberT ClassT::*memobjptr, ObjectT &&obj) noexcept( + noexcept(std::forward(obj).*memobjptr)) -> decltype(std::forward(obj).*memobjptr) + { + return std::forward(obj).*memobjptr; + } - template < - typename MemberT, typename ClassT, - typename ObjectT nsel_REQUIRES_T( - !std::is_same::type>::value && - !std::is_base_of< - ClassT, typename std20::remove_cvref::type>::value && - !is_reference_wrapper< - typename std20::remove_cvref::type>::value)> - nsel_constexpr auto - invoke_member_object_impl(MemberT ClassT::*memobjptr, ObjectT &&obj) noexcept( - noexcept((*std::forward(obj)).*memobjptr)) - -> decltype((*std::forward(obj)).*memobjptr) { - return (*std::forward(obj)).*memobjptr; - } + template::type>::value)> + nsel_constexpr auto invoke_member_object_impl(MemberT ClassT::*memobjptr, ObjectT &&obj) noexcept( + noexcept(obj.get().*memobjptr)) -> decltype(obj.get().*memobjptr) + { + return obj.get().*memobjptr; + } - template ::type>::value)> - nsel_constexpr auto invoke(F &&f, Args &&...args) noexcept( - noexcept(invoke_member_function_impl(std::forward(f), - std::forward(args)...))) - -> decltype(invoke_member_function_impl(std::forward(f), - std::forward(args)...)) { - return invoke_member_function_impl(std::forward(f), - std::forward(args)...); - } + template::type>::value + && !std::is_base_of::type>::value + && !is_reference_wrapper::type>::value)> + nsel_constexpr auto invoke_member_object_impl(MemberT ClassT::*memobjptr, ObjectT &&obj) noexcept( + noexcept((*std::forward(obj)).*memobjptr)) -> decltype((*std::forward(obj)).*memobjptr) + { + return (*std::forward(obj)).*memobjptr; + } - template ::type>::value)> - nsel_constexpr auto invoke(F &&f, Args &&...args) noexcept( - noexcept(invoke_member_object_impl(std::forward(f), - std::forward(args)...))) - -> decltype(invoke_member_object_impl(std::forward(f), - std::forward(args)...)) { - return invoke_member_object_impl(std::forward(f), - std::forward(args)...); - } + template< + typename F, + typename... Args nsel_REQUIRES_T(std::is_member_function_pointer::type>::value)> + nsel_constexpr auto invoke(F &&f, Args &&...args) noexcept( + noexcept(invoke_member_function_impl(std::forward(f), std::forward(args)...))) + -> decltype(invoke_member_function_impl(std::forward(f), std::forward(args)...)) + { + return invoke_member_function_impl(std::forward(f), std::forward(args)...); + } - template ::type>::value && - !std::is_member_object_pointer< - typename std20::remove_cvref::type>::value)> - nsel_constexpr auto invoke(F &&f, Args &&...args) noexcept( - noexcept(std::forward(f)(std::forward(args)...))) - -> decltype(std::forward(f)(std::forward(args)...)) { - return std::forward(f)(std::forward(args)...); - } + template< + typename F, + typename... Args nsel_REQUIRES_T(std::is_member_object_pointer::type>::value)> + nsel_constexpr auto invoke(F &&f, Args &&...args) noexcept( + noexcept(invoke_member_object_impl(std::forward(f), std::forward(args)...))) + -> decltype(invoke_member_object_impl(std::forward(f), std::forward(args)...)) + { + return invoke_member_object_impl(std::forward(f), std::forward(args)...); + } - template - using invoke_result_nocvref_t = typename std20::remove_cvref(), std::declval()...))>::type; + template::type>::value + && !std::is_member_object_pointer::type>::value)> + nsel_constexpr auto invoke(F &&f, Args &&...args) noexcept(noexcept( + std::forward(f)(std::forward(args)...))) -> decltype(std::forward(f)(std::forward(args)...)) + { + return std::forward(f)(std::forward(args)...); + } + + template + using invoke_result_nocvref_t = + typename std20::remove_cvref(), std::declval()...))>::type; #if nsel_P2505R >= 5 - template - using transform_invoke_result_t = typename std::remove_cv(), std::declval()...))>::type; + template + using transform_invoke_result_t = + typename std::remove_cv(), std::declval()...))>::type; #else - template - using transform_invoke_result_t = invoke_result_nocvref_t -#endif // nsel_P2505R >= 5 + template + using transform_invoke_result_t = invoke_result_nocvref_t +#endif// nsel_P2505R >= 5 - template - struct valid_expected_value_type - : std::integral_constant::value && - !std::is_reference::value && - !std::is_array::value> {}; + template + struct valid_expected_value_type + : std::integral_constant::value && !std::is_reference::value + && !std::is_array::value> {}; -#endif // nsel_P2505R >= 3 - } // namespace detail +#endif// nsel_P2505R >= 3 + }// namespace detail - /// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also - /// use aliased type unexpected. + /// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also + /// use aliased type unexpected. #if nsel_P0323R <= 2 - template - class unexpected_type + template + class unexpected_type #else - template - class unexpected_type -#endif // nsel_P0323R - { - public: - using error_type = E; + template + class unexpected_type +#endif// nsel_P0323R + { + public: + using error_type = E; - // x.x.5.2.1 Constructors + // x.x.5.2.1 Constructors - // unexpected_type() = delete; + // unexpected_type() = delete; - constexpr unexpected_type(unexpected_type const &) = default; - constexpr unexpected_type(unexpected_type &&) = default; + constexpr unexpected_type(unexpected_type const &) = default; + constexpr unexpected_type(unexpected_type &&) = default; - template ::value)> - constexpr explicit unexpected_type(nonstd_lite_in_place_t(E), - Args &&...args) - : m_error(std::forward(args)...) {} + template::value)> + constexpr explicit unexpected_type(nonstd_lite_in_place_t(E), Args &&...args) + : m_error(std::forward(args)...) + {} - template , - Args &&...>::value)> - constexpr explicit unexpected_type(nonstd_lite_in_place_t(E), - std::initializer_list il, - Args &&...args) - : m_error(il, std::forward(args)...) {} + template< + typename U, + typename... Args nsel_REQUIRES_T(std::is_constructible, Args &&...>::value)> + constexpr explicit unexpected_type(nonstd_lite_in_place_t(E), std::initializer_list il, Args &&...args) + : m_error(il, std::forward(args)...) + {} - template ::value && - !std::is_same::type, - nonstd_lite_in_place_t(E2)>::value && - !std::is_same::type, - unexpected_type>::value)> - constexpr explicit unexpected_type(E2 &&error) - : m_error(std::forward(error)) {} + template::value + && !std::is_same::type, nonstd_lite_in_place_t(E2)>::value + && !std::is_same::type, unexpected_type>::value)> + constexpr explicit unexpected_type(E2 &&error) : m_error(std::forward(error)) + {} - template ::value && - !std::is_constructible &>::value && - !std::is_constructible>::value && - !std::is_constructible const &>::value && - !std::is_constructible const>::value && - !std::is_convertible &, E>::value && - !std::is_convertible, E>::value && - !std::is_convertible const &, E>::value && - !std::is_convertible const, E>::value && - !std::is_convertible::value /*=> explicit */ - )> - constexpr explicit unexpected_type(unexpected_type const &error) - : m_error(E{error.value()}) {} + template::value && !std::is_constructible &>::value + && !std::is_constructible>::value + && !std::is_constructible const &>::value + && !std::is_constructible const>::value + && !std::is_convertible &, E>::value + && !std::is_convertible, E>::value + && !std::is_convertible const &, E>::value + && !std::is_convertible const, E>::value + && !std::is_convertible::value /*=> explicit */ + )> + constexpr explicit unexpected_type(unexpected_type const &error) : m_error(E{error.value()}) + {} - template ::value && - !std::is_constructible &>::value && - !std::is_constructible>::value && - !std::is_constructible const &>::value && - !std::is_constructible const>::value && - !std::is_convertible &, E>::value && - !std::is_convertible, E>::value && - !std::is_convertible const &, E>::value && - !std::is_convertible const, E>::value && - std::is_convertible::value /*=> explicit */ - )> - constexpr /*non-explicit*/ unexpected_type(unexpected_type const &error) - : m_error(error.value()) {} + template::value && !std::is_constructible &>::value + && !std::is_constructible>::value + && !std::is_constructible const &>::value + && !std::is_constructible const>::value + && !std::is_convertible &, E>::value + && !std::is_convertible, E>::value + && !std::is_convertible const &, E>::value + && !std::is_convertible const, E>::value + && std::is_convertible::value /*=> explicit */ + )> + constexpr /*non-explicit*/ unexpected_type(unexpected_type const &error) : m_error(error.value()) + {} - template ::value && - !std::is_constructible &>::value && - !std::is_constructible>::value && - !std::is_constructible const &>::value && - !std::is_constructible const>::value && - !std::is_convertible &, E>::value && - !std::is_convertible, E>::value && - !std::is_convertible const &, E>::value && - !std::is_convertible const, E>::value && - !std::is_convertible::value /*=> explicit */ - )> - constexpr explicit unexpected_type(unexpected_type &&error) - : m_error(E{std::move(error.value())}) {} + template::value && !std::is_constructible &>::value + && !std::is_constructible>::value + && !std::is_constructible const &>::value + && !std::is_constructible const>::value + && !std::is_convertible &, E>::value + && !std::is_convertible, E>::value + && !std::is_convertible const &, E>::value + && !std::is_convertible const, E>::value + && !std::is_convertible::value /*=> explicit */ + )> + constexpr explicit unexpected_type(unexpected_type &&error) : m_error(E{std::move(error.value())}) + {} - template ::value && - !std::is_constructible &>::value && - !std::is_constructible>::value && - !std::is_constructible const &>::value && - !std::is_constructible const>::value && - !std::is_convertible &, E>::value && - !std::is_convertible, E>::value && - !std::is_convertible const &, E>::value && - !std::is_convertible const, E>::value && - std::is_convertible::value /*=> non-explicit */ - )> - constexpr /*non-explicit*/ unexpected_type(unexpected_type &&error) - : m_error(std::move(error.value())) {} + template::value && !std::is_constructible &>::value + && !std::is_constructible>::value + && !std::is_constructible const &>::value + && !std::is_constructible const>::value + && !std::is_convertible &, E>::value + && !std::is_convertible, E>::value + && !std::is_convertible const &, E>::value + && !std::is_convertible const, E>::value + && std::is_convertible::value /*=> non-explicit */ + )> + constexpr /*non-explicit*/ unexpected_type(unexpected_type &&error) : m_error(std::move(error.value())) + {} - // x.x.5.2.2 Assignment + // x.x.5.2.2 Assignment - nsel_constexpr14 unexpected_type & - operator=(unexpected_type const &) = default; - nsel_constexpr14 unexpected_type &operator=(unexpected_type &&) = default; + nsel_constexpr14 unexpected_type &operator=(unexpected_type const &) = default; + nsel_constexpr14 unexpected_type &operator=(unexpected_type &&) = default; - template - nsel_constexpr14 unexpected_type & - operator=(unexpected_type const &other) { - unexpected_type{other.value()}.swap(*this); - return *this; - } + template + nsel_constexpr14 unexpected_type &operator=(unexpected_type const &other) + { + unexpected_type{other.value()}.swap(*this); + return *this; + } - template - nsel_constexpr14 unexpected_type &operator=(unexpected_type &&other) { - unexpected_type{std::move(other.value())}.swap(*this); - return *this; - } + template + nsel_constexpr14 unexpected_type &operator=(unexpected_type &&other) + { + unexpected_type{std::move(other.value())}.swap(*this); + return *this; + } - // x.x.5.2.3 Observers + // x.x.5.2.3 Observers - nsel_constexpr14 E &value() & noexcept { return m_error; } + nsel_constexpr14 E &value() & noexcept { return m_error; } - constexpr E const &value() const & noexcept { return m_error; } + constexpr E const &value() const & noexcept { return m_error; } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - nsel_constexpr14 E &&value() && noexcept { return std::move(m_error); } + nsel_constexpr14 E &&value() && noexcept { return std::move(m_error); } - constexpr E const &&value() const && noexcept { return std::move(m_error); } + constexpr E const &&value() const && noexcept { return std::move(m_error); } #endif - // x.x.5.2.4 Swap + // x.x.5.2.4 Swap - template - nsel_REQUIRES_R(void, std17::is_swappable::value) - swap(unexpected_type &other) noexcept( - std17::is_nothrow_swappable::value) { - using std::swap; - swap(m_error, other.m_error); - } + template + nsel_REQUIRES_R(void, std17::is_swappable::value) + swap(unexpected_type &other) noexcept(std17::is_nothrow_swappable::value) + { + using std::swap; + swap(m_error, other.m_error); + } - // TODO: ??? unexpected_type: in-class friend operator==, != + // TODO: ??? unexpected_type: in-class friend operator==, != - private: - error_type m_error; - }; + private: + error_type m_error; + }; #if nsel_CPP17_OR_GREATER - /// template deduction guide: + /// template deduction guide: - template unexpected_type(E) -> unexpected_type; + template + unexpected_type(E) -> unexpected_type; #endif - /// class unexpected_type, std::exception_ptr specialization (P0323R2) + /// class unexpected_type, std::exception_ptr specialization (P0323R2) #if !nsel_CONFIG_NO_EXCEPTIONS #if nsel_P0323R <= 2 - // TODO: Should expected be specialized for particular E types such as - // exception_ptr and how? - // See p0323r7 2.1. Ergonomics, http://wg21.link/p0323 - template <> class unexpected_type { - public: - using error_type = std::exception_ptr; + // TODO: Should expected be specialized for particular E types such as + // exception_ptr and how? + // See p0323r7 2.1. Ergonomics, http://wg21.link/p0323 + template<> + class unexpected_type { + public: + using error_type = std::exception_ptr; - unexpected_type() = delete; + unexpected_type() = delete; - ~unexpected_type() {} + ~unexpected_type() {} - explicit unexpected_type(std::exception_ptr const &error) - : m_error(error) {} + explicit unexpected_type(std::exception_ptr const &error) : m_error(error) {} - explicit unexpected_type(std::exception_ptr &&error) - : m_error(std::move(error)) {} + explicit unexpected_type(std::exception_ptr &&error) : m_error(std::move(error)) {} - template - explicit unexpected_type(E error) - : m_error(std::make_exception_ptr(error)) {} + template + explicit unexpected_type(E error) : m_error(std::make_exception_ptr(error)) + {} - std::exception_ptr const &value() const { return m_error; } + std::exception_ptr const &value() const { return m_error; } - std::exception_ptr &value() { return m_error; } + std::exception_ptr &value() { return m_error; } - private: - std::exception_ptr m_error; - }; + private: + std::exception_ptr m_error; + }; -#endif // nsel_P0323R -#endif // !nsel_CONFIG_NO_EXCEPTIONS +#endif// nsel_P0323R +#endif// !nsel_CONFIG_NO_EXCEPTIONS - /// x.x.4, Unexpected equality operators + /// x.x.4, Unexpected equality operators - template - constexpr bool operator==(unexpected_type const &x, - unexpected_type const &y) { - return x.value() == y.value(); - } - - template - constexpr bool operator!=(unexpected_type const &x, - unexpected_type const &y) { - return !(x == y); - } - -#if nsel_P0323R <= 2 - - template - constexpr bool operator<(unexpected_type const &x, - unexpected_type const &y) { - return x.value() < y.value(); - } - - template - constexpr bool operator>(unexpected_type const &x, - unexpected_type const &y) { - return (y < x); - } - - template - constexpr bool operator<=(unexpected_type const &x, - unexpected_type const &y) { - return !(y < x); - } - - template - constexpr bool operator>=(unexpected_type const &x, - unexpected_type const &y) { - return !(x < y); - } - -#endif // nsel_P0323R - - /// x.x.5 Specialized algorithms - - template ::value)> - void swap(unexpected_type &x, - unexpected_type &y) noexcept(noexcept(x.swap(y))) { - x.swap(y); - } - -#if nsel_P0323R <= 2 - - // unexpected: relational operators for std::exception_ptr: - - inline constexpr bool - operator<(unexpected_type const & /*x*/, - unexpected_type const & /*y*/) { - return false; - } - - inline constexpr bool - operator>(unexpected_type const & /*x*/, - unexpected_type const & /*y*/) { - return false; - } - - inline constexpr bool - operator<=(unexpected_type const &x, - unexpected_type const &y) { - return (x == y); - } - - inline constexpr bool - operator>=(unexpected_type const &x, - unexpected_type const &y) { - return (x == y); - } - -#endif // nsel_P0323R - - // unexpected: traits - -#if nsel_P0323R <= 3 - - template struct is_unexpected : std::false_type {}; - - template - struct is_unexpected> : std::true_type {}; - -#endif // nsel_P0323R - - // unexpected: factory - - // keep make_unexpected() removed in p0323r2 for pre-C++17: - - template - nsel_constexpr14 auto - make_unexpected(E &&value) -> unexpected_type::type> { - return unexpected_type::type>( - std::forward(value)); - } - -#if nsel_P0323R <= 3 - - /*nsel_constexpr14*/ auto inline make_unexpected_from_current_exception() - -> unexpected_type { - return unexpected_type(std::current_exception()); - } - -#endif // nsel_P0323R - - /// x.x.6, x.x.7 expected access error - - template class bad_expected_access; - - /// x.x.7 bad_expected_access: expected access error - - template <> class bad_expected_access : public std::exception { - public: - explicit bad_expected_access() : std::exception() {} - }; - - /// x.x.6 bad_expected_access: expected access error - -#if !nsel_CONFIG_NO_EXCEPTIONS - - template - class bad_expected_access : public bad_expected_access { - public: - using error_type = E; - - explicit bad_expected_access(error_type error) : m_error(error) {} - - virtual char const *what() const noexcept override { - return "bad_expected_access"; + template + constexpr bool operator==(unexpected_type const &x, unexpected_type const &y) + { + return x.value() == y.value(); } - nsel_constexpr14 error_type &error() & { return m_error; } + template + constexpr bool operator!=(unexpected_type const &x, unexpected_type const &y) + { + return !(x == y); + } - constexpr error_type const &error() const & { return m_error; } +#if nsel_P0323R <= 2 + + template + constexpr bool operator<(unexpected_type const &x, unexpected_type const &y) + { + return x.value() < y.value(); + } + + template + constexpr bool operator>(unexpected_type const &x, unexpected_type const &y) + { + return (y < x); + } + + template + constexpr bool operator<=(unexpected_type const &x, unexpected_type const &y) + { + return !(y < x); + } + + template + constexpr bool operator>=(unexpected_type const &x, unexpected_type const &y) + { + return !(x < y); + } + +#endif// nsel_P0323R + + /// x.x.5 Specialized algorithms + + template::value)> + void swap(unexpected_type &x, unexpected_type &y) noexcept(noexcept(x.swap(y))) + { + x.swap(y); + } + +#if nsel_P0323R <= 2 + + // unexpected: relational operators for std::exception_ptr: + + inline constexpr bool operator<(unexpected_type const & /*x*/, + unexpected_type const & /*y*/) + { + return false; + } + + inline constexpr bool operator>(unexpected_type const & /*x*/, + unexpected_type const & /*y*/) + { + return false; + } + + inline constexpr bool operator<=(unexpected_type const &x, + unexpected_type const &y) + { + return (x == y); + } + + inline constexpr bool operator>=(unexpected_type const &x, + unexpected_type const &y) + { + return (x == y); + } + +#endif// nsel_P0323R + + // unexpected: traits + +#if nsel_P0323R <= 3 + + template + struct is_unexpected : std::false_type {}; + + template + struct is_unexpected> : std::true_type {}; + +#endif// nsel_P0323R + + // unexpected: factory + + // keep make_unexpected() removed in p0323r2 for pre-C++17: + + template + nsel_constexpr14 auto make_unexpected(E &&value) -> unexpected_type::type> + { + return unexpected_type::type>(std::forward(value)); + } + +#if nsel_P0323R <= 3 + + /*nsel_constexpr14*/ auto inline make_unexpected_from_current_exception() -> unexpected_type + { + return unexpected_type(std::current_exception()); + } + +#endif// nsel_P0323R + + /// x.x.6, x.x.7 expected access error + + template + class bad_expected_access; + + /// x.x.7 bad_expected_access: expected access error + + template<> + class bad_expected_access : public std::exception { + public: + explicit bad_expected_access() : std::exception() {} + }; + + /// x.x.6 bad_expected_access: expected access error + +#if !nsel_CONFIG_NO_EXCEPTIONS + + template + class bad_expected_access : public bad_expected_access { + public: + using error_type = E; + + explicit bad_expected_access(error_type error) : m_error(error) {} + + virtual char const *what() const noexcept override { return "bad_expected_access"; } + + nsel_constexpr14 error_type &error() & { return m_error; } + + constexpr error_type const &error() const & { return m_error; } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - nsel_constexpr14 error_type &&error() && { return std::move(m_error); } + nsel_constexpr14 error_type &&error() && { return std::move(m_error); } - constexpr error_type const &&error() const && { return std::move(m_error); } + constexpr error_type const &&error() const && { return std::move(m_error); } #endif - private: - error_type m_error; - }; + private: + error_type m_error; + }; -#endif // nsel_CONFIG_NO_EXCEPTIONS +#endif// nsel_CONFIG_NO_EXCEPTIONS - /// x.x.8 unexpect tag, in_place_unexpected tag: construct an error + /// x.x.8 unexpect tag, in_place_unexpected tag: construct an error - struct unexpect_t {}; - using in_place_unexpected_t = unexpect_t; + struct unexpect_t {}; - nsel_inline17 constexpr unexpect_t unexpect{}; - nsel_inline17 constexpr unexpect_t in_place_unexpected{}; + using in_place_unexpected_t = unexpect_t; - /// class error_traits + nsel_inline17 constexpr unexpect_t unexpect{}; + nsel_inline17 constexpr unexpect_t in_place_unexpected{}; + + /// class error_traits #if nsel_CONFIG_NO_EXCEPTIONS - namespace detail { - inline bool text(char const * /*text*/) { return true; } - } // namespace detail + namespace detail { + inline bool text(char const * /*text*/) { return true; } + }// namespace detail - template struct error_traits { - static void rethrow(Error const & /*e*/) { + template + struct error_traits { + static void rethrow(Error const & /*e*/) + { #if nsel_CONFIG_NO_EXCEPTIONS_SEH - RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, - NULL); + RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL); #else - assert(false && detail::text("throw bad_expected_access{ e };")); + assert(false && detail::text("throw bad_expected_access{ e };")); #endif - } - }; - - template <> struct error_traits { - static void rethrow(std::exception_ptr const & /*e*/) { -#if nsel_CONFIG_NO_EXCEPTIONS_SEH - RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, - NULL); -#else - assert( - false && - detail::text("throw bad_expected_access{ e };")); -#endif - } - }; - - template <> struct error_traits { - static void rethrow(std::error_code const & /*e*/) { -#if nsel_CONFIG_NO_EXCEPTIONS_SEH - RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, - NULL); -#else - assert(false && detail::text("throw std::system_error( e );")); -#endif - } - }; - -#else // nsel_CONFIG_NO_EXCEPTIONS - - template struct error_traits { - static void rethrow(Error const &e) { throw bad_expected_access{e}; } - }; - - template <> struct error_traits { - static void rethrow(std::exception_ptr const &e) { - std::rethrow_exception(e); - } - }; - - template <> struct error_traits { - static void rethrow(std::error_code const &e) { - throw std::system_error(e); - } - }; - -#endif // nsel_CONFIG_NO_EXCEPTIONS - -#if nsel_P2505R >= 3 - namespace detail { - - // from https://en.cppreference.com/w/cpp/utility/expected/unexpected: - // "the type of the unexpected value. The type must not be an array type, a - // non-object type, a specialization of std::unexpected, or a cv-qualified - // type." - template - struct valid_unexpected_type - : std::integral_constant< - bool, - std::is_same::type>::value && - std::is_object::value && !std::is_array::value> {}; - - template - struct valid_unexpected_type> : std::false_type {}; - - } // namespace detail -#endif // nsel_P2505R >= 3 - - } // namespace expected_lite - - // provide nonstd::unexpected_type: - - using expected_lite::unexpected_type; - - namespace expected_lite { - - /// class expected - -#if nsel_P0323R <= 2 - template - class expected -#else - template - class expected -#endif // nsel_P0323R - { - private: - template friend class expected; - - public: - using value_type = T; - using error_type = E; - using unexpected_type = nonstd::unexpected_type; - - template struct rebind { - using type = expected; + } }; - // x.x.4.1 constructors + template<> + struct error_traits { + static void rethrow(std::exception_ptr const & /*e*/) + { +#if nsel_CONFIG_NO_EXCEPTIONS_SEH + RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL); +#else + assert(false && detail::text("throw bad_expected_access{ e };")); +#endif + } + }; - nsel_REQUIRES_0(std::is_default_constructible::value) nsel_constexpr14 - expected() - : contained(true) { - contained.construct_value(); - } + template<> + struct error_traits { + static void rethrow(std::error_code const & /*e*/) + { +#if nsel_CONFIG_NO_EXCEPTIONS_SEH + RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL); +#else + assert(false && detail::text("throw std::system_error( e );")); +#endif + } + }; - nsel_constexpr14 expected(expected const &) = default; - nsel_constexpr14 expected(expected &&) = default; +#else// nsel_CONFIG_NO_EXCEPTIONS - template ::value - &&std::is_constructible::value && - !std::is_constructible &>::value && - !std::is_constructible &&>::value && - !std::is_constructible const &>::value && - !std::is_constructible const &&>::value && - !std::is_convertible &, T>::value && - !std::is_convertible &&, T>::value && - !std::is_convertible const &, T>::value && - !std::is_convertible const &&, T>::value && - (!std::is_convertible::value || - !std::is_convertible::value) /*=> explicit */ - )> - nsel_constexpr14 explicit expected(expected const &other) - : contained(other.has_value()) { - if (has_value()) - contained.construct_value(T{other.contained.value()}); - else - contained.construct_error(E{other.contained.error()}); - } + template + struct error_traits { + static void rethrow(Error const &e) { throw bad_expected_access{e}; } + }; - template ::value - &&std::is_constructible::value && - !std::is_constructible &>::value && - !std::is_constructible &&>::value && - !std::is_constructible const &>::value && - !std::is_constructible const &&>::value && - !std::is_convertible &, T>::value && - !std::is_convertible &&, T>::value && - !std::is_convertible const &, T>::value && - !std::is_convertible const &&, T>::value && - !(!std::is_convertible::value || - !std::is_convertible::value) /*=> non-explicit - */ - )> - nsel_constexpr14 /*non-explicit*/ expected(expected const &other) - : contained(other.has_value()) { - if (has_value()) - contained.construct_value(other.contained.value()); - else - contained.construct_error(other.contained.error()); - } + template<> + struct error_traits { + static void rethrow(std::exception_ptr const &e) { std::rethrow_exception(e); } + }; - template ::value - &&std::is_constructible::value && - !std::is_constructible &>::value && - !std::is_constructible &&>::value && - !std::is_constructible const &>::value && - !std::is_constructible const &&>::value && - !std::is_convertible &, T>::value && - !std::is_convertible &&, T>::value && - !std::is_convertible const &, T>::value && - !std::is_convertible const &&, T>::value && - (!std::is_convertible::value || - !std::is_convertible::value) /*=> explicit */ - )> - nsel_constexpr14 explicit expected(expected &&other) - : contained(other.has_value()) { - if (has_value()) - contained.construct_value(T{std::move(other.contained.value())}); - else - contained.construct_error(E{std::move(other.contained.error())}); - } + template<> + struct error_traits { + static void rethrow(std::error_code const &e) { throw std::system_error(e); } + }; - template ::value - &&std::is_constructible::value && - !std::is_constructible &>::value && - !std::is_constructible &&>::value && - !std::is_constructible const &>::value && - !std::is_constructible const &&>::value && - !std::is_convertible &, T>::value && - !std::is_convertible &&, T>::value && - !std::is_convertible const &, T>::value && - !std::is_convertible const &&, T>::value && - !(!std::is_convertible::value || - !std::is_convertible::value) /*=> non-explicit */ - )> - nsel_constexpr14 /*non-explicit*/ expected(expected &&other) - : contained(other.has_value()) { - if (has_value()) - contained.construct_value(std::move(other.contained.value())); - else - contained.construct_error(std::move(other.contained.error())); - } +#endif// nsel_CONFIG_NO_EXCEPTIONS - template < - typename U = T nsel_REQUIRES_T(std::is_copy_constructible::value)> - nsel_constexpr14 expected(value_type const &value) : contained(true) { - contained.construct_value(value); - } +#if nsel_P2505R >= 3 + namespace detail { - template ::value && - !std::is_same::type, - nonstd_lite_in_place_t(U)>::value && - !std::is_same, - typename std20::remove_cvref::type>::value && - !std::is_same, - typename std20::remove_cvref::type>::value && - !std::is_convertible::value /*=> explicit */ - )> - nsel_constexpr14 explicit expected(U &&value) noexcept( - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value) - : contained(true) { - contained.construct_value(T{std::forward(value)}); - } + // from https://en.cppreference.com/w/cpp/utility/expected/unexpected: + // "the type of the unexpected value. The type must not be an array type, a + // non-object type, a specialization of std::unexpected, or a cv-qualified + // type." + template + struct valid_unexpected_type + : std::integral_constant::type>::value + && std::is_object::value && !std::is_array::value> {}; - template ::value && - !std::is_same::type, - nonstd_lite_in_place_t(U)>::value && - !std::is_same, - typename std20::remove_cvref::type>::value && - !std::is_same, - typename std20::remove_cvref::type>::value && - std::is_convertible::value /*=> non-explicit */ - )> - nsel_constexpr14 /*non-explicit*/ - expected(U &&value) noexcept(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value) - : contained(true) { - contained.construct_value(std::forward(value)); - } + template + struct valid_unexpected_type> : std::false_type {}; - // construct error: + }// namespace detail +#endif// nsel_P2505R >= 3 - template ::value && - !std::is_convertible::value /*=> explicit */ - )> - nsel_constexpr14 explicit expected(nonstd::unexpected_type const &error) - : contained(false) { - contained.construct_error(E{error.value()}); - } + }// namespace expected_lite - template ::value && - std::is_convertible::value /*=> non-explicit - */ - )> - nsel_constexpr14 /*non-explicit*/ - expected(nonstd::unexpected_type const &error) - : contained(false) { - contained.construct_error(error.value()); - } + // provide nonstd::unexpected_type: - template ::value && - !std::is_convertible::value /*=> explicit */ - )> - nsel_constexpr14 explicit expected(nonstd::unexpected_type &&error) - : contained(false) { - contained.construct_error(E{std::move(error.value())}); - } + using expected_lite::unexpected_type; - template ::value - &&std::is_convertible::value /*=> non-explicit */ - )> - nsel_constexpr14 /*non-explicit*/ - expected(nonstd::unexpected_type &&error) - : contained(false) { - contained.construct_error(std::move(error.value())); - } + namespace expected_lite { - // in-place construction, value + /// class expected - template ::value)> - nsel_constexpr14 explicit expected(nonstd_lite_in_place_t(T), - Args &&...args) - : contained(true) { - contained.emplace_value(std::forward(args)...); - } - - template , - Args &&...>::value)> - nsel_constexpr14 explicit expected(nonstd_lite_in_place_t(T), - std::initializer_list il, - Args &&...args) - : contained(true) { - contained.emplace_value(il, std::forward(args)...); - } - - // in-place construction, error - - template ::value)> - nsel_constexpr14 explicit expected(unexpect_t, Args &&...args) - : contained(false) { - contained.emplace_error(std::forward(args)...); - } - - template , - Args &&...>::value)> - nsel_constexpr14 explicit expected(unexpect_t, std::initializer_list il, - Args &&...args) - : contained(false) { - contained.emplace_error(il, std::forward(args)...); - } - - // x.x.4.2 destructor - - // TODO: ~expected: triviality - // Effects: If T is not cv void and is_trivially_destructible_v is false - // and bool(*this), calls val.~T(). If is_trivially_destructible_v is - // false and !bool(*this), calls unexpect.~unexpected(). Remarks: If - // either T is cv void or is_trivially_destructible_v is true, and - // is_trivially_destructible_v is true, then this destructor shall be a - // trivial destructor. - - ~expected() { - if (has_value()) - contained.destruct_value(); - else - contained.destruct_error(); - } - - // x.x.4.3 assignment - - expected &operator=(expected const &other) { - expected(other).swap(*this); - return *this; - } - - expected &operator=(expected &&other) noexcept( - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_assignable::value && - std::is_nothrow_move_constructible::value // added for missing - && std::is_nothrow_move_assignable::value) // nothrow above +#if nsel_P0323R <= 2 + template + class expected +#else + template + class expected +#endif// nsel_P0323R { - expected(std::move(other)).swap(*this); - return *this; - } + private: + template + friend class expected; - template , - typename std20::remove_cvref::type>::value && - std17::conjunction, - std::is_same>>::value && - std::is_constructible::value && - std::is_assignable::value && - std::is_nothrow_move_constructible::value)> - expected &operator=(U &&value) { - expected(std::forward(value)).swap(*this); - return *this; - } + public: + using value_type = T; + using error_type = E; + using unexpected_type = nonstd::unexpected_type; - template ::value - &&std::is_copy_constructible:: - value // TODO: std::is_nothrow_copy_constructible - &&std::is_copy_assignable::value)> - expected &operator=(nonstd::unexpected_type const &error) { - expected(unexpect, error.value()).swap(*this); - return *this; - } + template + struct rebind { + using type = expected; + }; - template < - typename G = E nsel_REQUIRES_T( - std::is_constructible::value &&std::is_move_constructible< - G>::value // TODO: std::is_nothrow_move_constructible - &&std::is_move_assignable::value)> - expected &operator=(nonstd::unexpected_type &&error) { - expected(unexpect, std::move(error.value())).swap(*this); - return *this; - } + // x.x.4.1 constructors - template ::value)> - value_type &emplace(Args &&...args) { - expected(nonstd_lite_in_place(T), std::forward(args)...) - .swap(*this); - return value(); - } + nsel_REQUIRES_0(std::is_default_constructible::value) nsel_constexpr14 expected() : contained(true) + { + contained.construct_value(); + } - template &, - Args &&...>::value)> - value_type &emplace(std::initializer_list il, Args &&...args) { - expected(nonstd_lite_in_place(T), il, std::forward(args)...) - .swap(*this); - return value(); - } + nsel_constexpr14 expected(expected const &) = default; + nsel_constexpr14 expected(expected &&) = default; - // x.x.4.4 swap + template::value &&std::is_constructible::value + && !std::is_constructible &>::value + && !std::is_constructible &&>::value + && !std::is_constructible const &>::value + && !std::is_constructible const &&>::value + && !std::is_convertible &, T>::value + && !std::is_convertible &&, T>::value + && !std::is_convertible const &, T>::value + && !std::is_convertible const &&, T>::value + && (!std::is_convertible::value + || !std::is_convertible::value) /*=> explicit */ + )> + nsel_constexpr14 explicit expected(expected const &other) : contained(other.has_value()) + { + if (has_value()) + contained.construct_value(T{other.contained.value()}); + else + contained.construct_error(E{other.contained.error()}); + } - template - nsel_REQUIRES_R( - void, std17::is_swappable::value &&std17::is_swappable::value && - (std::is_move_constructible::value || - std::is_move_constructible::value)) - swap(expected &other) noexcept( - std::is_nothrow_move_constructible::value && - std17::is_nothrow_swappable::value && - std::is_nothrow_move_constructible::value && - std17::is_nothrow_swappable::value) { - using std::swap; + template::value &&std::is_constructible::value + && !std::is_constructible &>::value + && !std::is_constructible &&>::value + && !std::is_constructible const &>::value + && !std::is_constructible const &&>::value + && !std::is_convertible &, T>::value + && !std::is_convertible &&, T>::value + && !std::is_convertible const &, T>::value + && !std::is_convertible const &&, T>::value + && !(!std::is_convertible::value + || !std::is_convertible::value) /*=> non-explicit + */ + )> + nsel_constexpr14 /*non-explicit*/ expected(expected const &other) : contained(other.has_value()) + { + if (has_value()) + contained.construct_value(other.contained.value()); + else + contained.construct_error(other.contained.error()); + } - if (bool(*this) && bool(other)) { - swap(contained.value(), other.contained.value()); - } else if (!bool(*this) && !bool(other)) { - swap(contained.error(), other.contained.error()); - } else if (bool(*this) && !bool(other)) { - error_type t(std::move(other.error())); - other.contained.destruct_error(); - other.contained.construct_value(std::move(contained.value())); - contained.destruct_value(); - contained.construct_error(std::move(t)); - bool has_value = contained.has_value(); - bool other_has_value = other.has_value(); - other.contained.set_has_value(has_value); - contained.set_has_value(other_has_value); - } else if (!bool(*this) && bool(other)) { - other.swap(*this); - } - } + template::value &&std::is_constructible::value + && !std::is_constructible &>::value + && !std::is_constructible &&>::value + && !std::is_constructible const &>::value + && !std::is_constructible const &&>::value + && !std::is_convertible &, T>::value + && !std::is_convertible &&, T>::value + && !std::is_convertible const &, T>::value + && !std::is_convertible const &&, T>::value + && (!std::is_convertible::value || !std::is_convertible::value) /*=> explicit */ + )> + nsel_constexpr14 explicit expected(expected &&other) : contained(other.has_value()) + { + if (has_value()) + contained.construct_value(T{std::move(other.contained.value())}); + else + contained.construct_error(E{std::move(other.contained.error())}); + } - // x.x.4.5 observers + template::value &&std::is_constructible::value + && !std::is_constructible &>::value + && !std::is_constructible &&>::value + && !std::is_constructible const &>::value + && !std::is_constructible const &&>::value + && !std::is_convertible &, T>::value + && !std::is_convertible &&, T>::value + && !std::is_convertible const &, T>::value + && !std::is_convertible const &&, T>::value + && !(!std::is_convertible::value || !std::is_convertible::value) /*=> non-explicit */ + )> + nsel_constexpr14 /*non-explicit*/ expected(expected &&other) : contained(other.has_value()) + { + if (has_value()) + contained.construct_value(std::move(other.contained.value())); + else + contained.construct_error(std::move(other.contained.error())); + } - constexpr value_type const *operator->() const { - return assert(has_value()), contained.value_ptr(); - } + template::value)> + nsel_constexpr14 expected(value_type const &value) : contained(true) + { + contained.construct_value(value); + } - value_type *operator->() { - return assert(has_value()), contained.value_ptr(); - } + template::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && !std::is_convertible::value /*=> explicit */ + )> + nsel_constexpr14 explicit expected(U &&value) noexcept(std::is_nothrow_move_constructible::value + && std::is_nothrow_move_constructible::value) + : contained(true) + { + contained.construct_value(T{std::forward(value)}); + } - constexpr value_type const &operator*() const & { - return assert(has_value()), contained.value(); - } + template::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && std::is_convertible::value /*=> non-explicit */ + )> + nsel_constexpr14 /*non-explicit*/ + expected(U &&value) noexcept(std::is_nothrow_move_constructible::value + && std::is_nothrow_move_constructible::value) + : contained(true) + { + contained.construct_value(std::forward(value)); + } - value_type &operator*() & { return assert(has_value()), contained.value(); } + // construct error: + + template::value + && !std::is_convertible::value /*=> explicit */ + )> + nsel_constexpr14 explicit expected(nonstd::unexpected_type const &error) : contained(false) + { + contained.construct_error(E{error.value()}); + } + + template::value + &&std::is_convertible::value /*=> non-explicit + */ + )> + nsel_constexpr14 /*non-explicit*/ + expected(nonstd::unexpected_type const &error) + : contained(false) + { + contained.construct_error(error.value()); + } + + template::value + && !std::is_convertible::value /*=> explicit */ + )> + nsel_constexpr14 explicit expected(nonstd::unexpected_type &&error) : contained(false) + { + contained.construct_error(E{std::move(error.value())}); + } + + template::value &&std::is_convertible::value /*=> non-explicit */ + )> + nsel_constexpr14 /*non-explicit*/ + expected(nonstd::unexpected_type &&error) + : contained(false) + { + contained.construct_error(std::move(error.value())); + } + + // in-place construction, value + + template::value)> + nsel_constexpr14 explicit expected(nonstd_lite_in_place_t(T), Args &&...args) : contained(true) + { + contained.emplace_value(std::forward(args)...); + } + + template< + typename U, + typename... Args nsel_REQUIRES_T(std::is_constructible, Args &&...>::value)> + nsel_constexpr14 explicit expected(nonstd_lite_in_place_t(T), std::initializer_list il, Args &&...args) + : contained(true) + { + contained.emplace_value(il, std::forward(args)...); + } + + // in-place construction, error + + template::value)> + nsel_constexpr14 explicit expected(unexpect_t, Args &&...args) : contained(false) + { + contained.emplace_error(std::forward(args)...); + } + + template< + typename U, + typename... Args nsel_REQUIRES_T(std::is_constructible, Args &&...>::value)> + nsel_constexpr14 explicit expected(unexpect_t, std::initializer_list il, Args &&...args) : contained(false) + { + contained.emplace_error(il, std::forward(args)...); + } + + // x.x.4.2 destructor + + // TODO: ~expected: triviality + // Effects: If T is not cv void and is_trivially_destructible_v is false + // and bool(*this), calls val.~T(). If is_trivially_destructible_v is + // false and !bool(*this), calls unexpect.~unexpected(). Remarks: If + // either T is cv void or is_trivially_destructible_v is true, and + // is_trivially_destructible_v is true, then this destructor shall be a + // trivial destructor. + + ~expected() + { + if (has_value()) + contained.destruct_value(); + else + contained.destruct_error(); + } + + // x.x.4.3 assignment + + expected &operator=(expected const &other) + { + expected(other).swap(*this); + return *this; + } + + expected &operator=(expected &&other) noexcept( + std::is_nothrow_move_constructible::value && std::is_nothrow_move_assignable::value + && std::is_nothrow_move_constructible::value// added for missing + && std::is_nothrow_move_assignable::value) // nothrow above + { + expected(std::move(other)).swap(*this); + return *this; + } + + template, typename std20::remove_cvref::type>::value + && std17::conjunction, std::is_same>>::value + && std::is_constructible::value && std::is_assignable::value + && std::is_nothrow_move_constructible::value)> + expected &operator=(U &&value) + { + expected(std::forward(value)).swap(*this); + return *this; + } + + template::value &&std::is_copy_constructible< + G>::value// TODO: std::is_nothrow_copy_constructible + &&std::is_copy_assignable::value)> + expected &operator=(nonstd::unexpected_type const &error) + { + expected(unexpect, error.value()).swap(*this); + return *this; + } + + template::value &&std::is_move_constructible< + G>::value// TODO: std::is_nothrow_move_constructible + &&std::is_move_assignable::value)> + expected &operator=(nonstd::unexpected_type &&error) + { + expected(unexpect, std::move(error.value())).swap(*this); + return *this; + } + + template::value)> + value_type &emplace(Args &&...args) + { + expected(nonstd_lite_in_place(T), std::forward(args)...).swap(*this); + return value(); + } + + template &, Args &&...>::value)> + value_type &emplace(std::initializer_list il, Args &&...args) + { + expected(nonstd_lite_in_place(T), il, std::forward(args)...).swap(*this); + return value(); + } + + // x.x.4.4 swap + + template + nsel_REQUIRES_R(void, + std17::is_swappable::value &&std17::is_swappable::value + && (std::is_move_constructible::value || std::is_move_constructible::value)) + swap(expected &other) noexcept( + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value + && std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value) + { + using std::swap; + + if (bool(*this) && bool(other)) { + swap(contained.value(), other.contained.value()); + } else if (!bool(*this) && !bool(other)) { + swap(contained.error(), other.contained.error()); + } else if (bool(*this) && !bool(other)) { + error_type t(std::move(other.error())); + other.contained.destruct_error(); + other.contained.construct_value(std::move(contained.value())); + contained.destruct_value(); + contained.construct_error(std::move(t)); + bool has_value = contained.has_value(); + bool other_has_value = other.has_value(); + other.contained.set_has_value(has_value); + contained.set_has_value(other_has_value); + } else if (!bool(*this) && bool(other)) { + other.swap(*this); + } + } + + // x.x.4.5 observers + + constexpr value_type const *operator->() const { return assert(has_value()), contained.value_ptr(); } + + value_type *operator->() { return assert(has_value()), contained.value_ptr(); } + + constexpr value_type const &operator*() const & { return assert(has_value()), contained.value(); } + + value_type &operator*() & { return assert(has_value()), contained.value(); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - constexpr value_type const &&operator*() const && { - return std::move((assert(has_value()), contained.value())); - } + constexpr value_type const &&operator*() const && + { + return std::move((assert(has_value()), contained.value())); + } - nsel_constexpr14 value_type &&operator*() && { - return std::move((assert(has_value()), contained.value())); - } + nsel_constexpr14 value_type &&operator*() && { return std::move((assert(has_value()), contained.value())); } #endif - constexpr explicit operator bool() const noexcept { return has_value(); } + constexpr explicit operator bool() const noexcept { return has_value(); } - constexpr bool has_value() const noexcept { return contained.has_value(); } + constexpr bool has_value() const noexcept { return contained.has_value(); } - constexpr value_type const &value() const & { - return has_value() - ? (contained.value()) - : (error_traits::rethrow(contained.error()), - contained.value()); - } + constexpr value_type const &value() const & + { + return has_value() ? (contained.value()) + : (error_traits::rethrow(contained.error()), contained.value()); + } - value_type &value() & { - return has_value() - ? (contained.value()) - : (error_traits::rethrow(contained.error()), - contained.value()); - } + value_type &value() & + { + return has_value() ? (contained.value()) + : (error_traits::rethrow(contained.error()), contained.value()); + } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - constexpr value_type const &&value() const && { - return std::move( - has_value() ? (contained.value()) - : (error_traits::rethrow(contained.error()), - contained.value())); - } + constexpr value_type const &&value() const && + { + return std::move(has_value() ? (contained.value()) + : (error_traits::rethrow(contained.error()), contained.value())); + } - nsel_constexpr14 value_type &&value() && { - return std::move( - has_value() ? (contained.value()) - : (error_traits::rethrow(contained.error()), - contained.value())); - } + nsel_constexpr14 value_type &&value() && + { + return std::move(has_value() ? (contained.value()) + : (error_traits::rethrow(contained.error()), contained.value())); + } #endif - constexpr error_type const &error() const & { - return assert(!has_value()), contained.error(); - } + constexpr error_type const &error() const & { return assert(!has_value()), contained.error(); } - error_type &error() & { return assert(!has_value()), contained.error(); } + error_type &error() & { return assert(!has_value()), contained.error(); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - constexpr error_type const &&error() const && { - return std::move((assert(!has_value()), contained.error())); - } + constexpr error_type const &&error() const && { return std::move((assert(!has_value()), contained.error())); } - error_type &&error() && { - return std::move((assert(!has_value()), contained.error())); - } + error_type &&error() && { return std::move((assert(!has_value()), contained.error())); } #endif - constexpr unexpected_type get_unexpected() const { - return make_unexpected(contained.error()); - } + constexpr unexpected_type get_unexpected() const { return make_unexpected(contained.error()); } - template bool has_exception() const { - using ContainedEx = typename std::remove_reference< - decltype(get_unexpected().value())>::type; - return !has_value() && std::is_base_of::value; - } + template + bool has_exception() const + { + using ContainedEx = typename std::remove_reference::type; + return !has_value() && std::is_base_of::value; + } - template < - typename U nsel_REQUIRES_T(std::is_copy_constructible::value - &&std::is_convertible::value)> - value_type value_or(U &&v) const & { - return has_value() ? contained.value() - : static_cast(std::forward(v)); - } + template::value &&std::is_convertible::value)> + value_type value_or(U &&v) const & + { + return has_value() ? contained.value() : static_cast(std::forward(v)); + } - template < - typename U nsel_REQUIRES_T(std::is_move_constructible::value - &&std::is_convertible::value)> - value_type value_or(U &&v) && { - return has_value() ? std::move(contained.value()) - : static_cast(std::forward(v)); - } + template::value &&std::is_convertible::value)> + value_type value_or(U &&v) && + { + return has_value() ? std::move(contained.value()) : static_cast(std::forward(v)); + } #if nsel_P2505R >= 4 - template < - typename G = E nsel_REQUIRES_T(std::is_copy_constructible::value - &&std::is_convertible::value)> - nsel_constexpr error_type error_or(G &&e) const & { - return has_value() ? static_cast(std::forward(e)) - : contained.error(); - } + template< + typename G = E nsel_REQUIRES_T(std::is_copy_constructible::value &&std::is_convertible::value)> + nsel_constexpr error_type error_or(G &&e) const & + { + return has_value() ? static_cast(std::forward(e)) : contained.error(); + } - template < - typename G = E nsel_REQUIRES_T(std::is_move_constructible::value - &&std::is_convertible::value)> - nsel_constexpr14 error_type error_or(G &&e) && { - return has_value() ? static_cast(std::forward(e)) - : std::move(contained.error()); - } -#endif // nsel_P2505R >= 4 + template< + typename G = E nsel_REQUIRES_T(std::is_move_constructible::value &&std::is_convertible::value)> + nsel_constexpr14 error_type error_or(G &&e) && + { + return has_value() ? static_cast(std::forward(e)) : std::move(contained.error()); + } +#endif// nsel_P2505R >= 4 #if nsel_P2505R >= 3 - // Monadic operations (P2505) - template >:: - value &&std::is_same::error_type, - error_type>::value - &&std::is_constructible::value)> - nsel_constexpr14 detail::invoke_result_nocvref_t - and_then(F &&f) & { - return has_value() ? detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), value())) - : detail::invoke_result_nocvref_t( - unexpect, error()); - } + // Monadic operations (P2505) + template>::value + &&std::is_same::error_type, error_type>::value + &&std::is_constructible::value)> + nsel_constexpr14 detail::invoke_result_nocvref_t and_then(F &&f) & + { + return has_value() + ? detail::invoke_result_nocvref_t(detail::invoke(std::forward(f), value())) + : detail::invoke_result_nocvref_t(unexpect, error()); + } - template >::value - &&std::is_same::error_type, - error_type>::value - &&std::is_constructible::value)> - nsel_constexpr detail::invoke_result_nocvref_t - and_then(F &&f) const & { - return has_value() - ? detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), value())) - : detail::invoke_result_nocvref_t( - unexpect, error()); - } + template>::value + &&std::is_same::error_type, + error_type>::value &&std::is_constructible::value)> + nsel_constexpr detail::invoke_result_nocvref_t and_then(F &&f) const & + { + return has_value() + ? detail::invoke_result_nocvref_t(detail::invoke(std::forward(f), value())) + : detail::invoke_result_nocvref_t(unexpect, error()); + } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - template >:: - value &&std::is_same::error_type, - error_type>::value - &&std::is_constructible::value)> - nsel_constexpr14 detail::invoke_result_nocvref_t - and_then(F &&f) && { - return has_value() - ? detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), std::move(value()))) - : detail::invoke_result_nocvref_t( - unexpect, std::move(error())); - } + template>::value && + std::is_same::error_type, error_type>::value + &&std::is_constructible::value)> + nsel_constexpr14 detail::invoke_result_nocvref_t and_then(F &&f) && + { + return has_value() + ? detail::invoke_result_nocvref_t( + detail::invoke(std::forward(f), std::move(value()))) + : detail::invoke_result_nocvref_t(unexpect, std::move(error())); + } - template >::value - &&std::is_same::error_type, - error_type>::value && - std::is_constructible::value)> - nsel_constexpr detail::invoke_result_nocvref_t - and_then(F &&f) const && { - return has_value() - ? detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), std::move(value()))) - : detail::invoke_result_nocvref_t( - unexpect, std::move(error())); - } + template>::value + &&std::is_same::error_type, + error_type>::value &&std::is_constructible::value)> + nsel_constexpr detail::invoke_result_nocvref_t and_then(F &&f) const && + { + return has_value() + ? detail::invoke_result_nocvref_t( + detail::invoke(std::forward(f), std::move(value()))) + : detail::invoke_result_nocvref_t(unexpect, std::move(error())); + } #endif - template >:: - value &&std::is_same::value_type, - value_type>::value + template>::value + &&std::is_same::value_type, value_type>::value + &&std::is_constructible::value)> + nsel_constexpr14 detail::invoke_result_nocvref_t or_else(F &&f) & + { + return has_value() + ? detail::invoke_result_nocvref_t(value()) + : detail::invoke_result_nocvref_t(detail::invoke(std::forward(f), error())); + } + + template>::value + &&std::is_same::value_type, + value_type>::value &&std::is_constructible::value)> + nsel_constexpr detail::invoke_result_nocvref_t or_else(F &&f) const & + { + return has_value() + ? detail::invoke_result_nocvref_t(value()) + : detail::invoke_result_nocvref_t(detail::invoke(std::forward(f), error())); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template>::value && + std::is_same::value_type, value_type>::value + &&std::is_constructible::value)> + nsel_constexpr14 detail::invoke_result_nocvref_t or_else(F &&f) && + { + return has_value() + ? detail::invoke_result_nocvref_t(std::move(value())) + : detail::invoke_result_nocvref_t( + detail::invoke(std::forward(f), std::move(error()))); + } + + template>::value + &&std::is_same::value_type, + value_type>::value &&std::is_constructible::value)> + nsel_constexpr detail::invoke_result_nocvref_t or_else(F &&f) const && + { + return has_value() + ? detail::invoke_result_nocvref_t(std::move(value())) + : detail::invoke_result_nocvref_t( + detail::invoke(std::forward(f), std::move(error()))); + } +#endif + + template::value + && !std::is_void>::value + && detail::valid_expected_value_type>::value)> + nsel_constexpr14 expected, error_type> transform(F &&f) & + { + return has_value() + ? expected, error_type>( + detail::invoke(std::forward(f), **this)) + : make_unexpected(error()); + } + + template::value &&std::is_void< + detail::transform_invoke_result_t>::value)> + nsel_constexpr14 expected transform(F &&f) & + { + return has_value() ? (detail::invoke(std::forward(f), **this), expected()) + : make_unexpected(error()); + } + + template::value + && !std::is_void>::value + && detail::valid_expected_value_type>::value)> + nsel_constexpr expected, error_type> + transform(F &&f) const & + { + return has_value() + ? expected, error_type>( + detail::invoke(std::forward(f), **this)) + : make_unexpected(error()); + } + + template::value &&std::is_void< + detail::transform_invoke_result_t>::value)> + nsel_constexpr expected transform(F &&f) const & + { + return has_value() ? (detail::invoke(std::forward(f), **this), expected()) + : make_unexpected(error()); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template::value + && !std::is_void>::value + && detail::valid_expected_value_type>::value)> + nsel_constexpr14 expected, error_type> transform(F &&f) && + { + return has_value() + ? expected, error_type>( + detail::invoke(std::forward(f), std::move(**this))) + : make_unexpected(std::move(error())); + } + + template::value &&std::is_void< + detail::transform_invoke_result_t>::value)> + nsel_constexpr14 expected transform(F &&f) && + { + return has_value() ? (detail::invoke(std::forward(f), **this), expected()) + : make_unexpected(std::move(error())); + } + + template::value + && !std::is_void>::value + && detail::valid_expected_value_type>::value)> + nsel_constexpr expected, error_type> + transform(F &&f) const && + { + return has_value() + ? expected, error_type>( + detail::invoke(std::forward(f), std::move(**this))) + : make_unexpected(std::move(error())); + } + + template::value + &&std::is_void>::value)> + nsel_constexpr expected transform(F &&f) const && + { + return has_value() ? (detail::invoke(std::forward(f), **this), expected()) + : make_unexpected(std::move(error())); + } +#endif + + template>::value &&std::is_constructible::value)> - nsel_constexpr14 detail::invoke_result_nocvref_t - or_else(F &&f) & { - return has_value() - ? detail::invoke_result_nocvref_t(value()) - : detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), error())); - } + nsel_constexpr14 expected> + transform_error(F &&f) & + { + return has_value() + ? expected>(in_place, **this) + : make_unexpected(detail::invoke(std::forward(f), error())); + } - template >::value - &&std::is_same::value_type, - value_type>::value + template>::value &&std::is_constructible::value)> - nsel_constexpr detail::invoke_result_nocvref_t - or_else(F &&f) const & { - return has_value() - ? detail::invoke_result_nocvref_t( - value()) - : detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), error())); - } + nsel_constexpr expected> + transform_error(F &&f) const & + { + return has_value() + ? expected>(in_place, **this) + : make_unexpected(detail::invoke(std::forward(f), error())); + } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - template >:: - value &&std::is_same::value_type, - value_type>::value + template>::value &&std::is_constructible::value)> - nsel_constexpr14 detail::invoke_result_nocvref_t - or_else(F &&f) && { - return has_value() - ? detail::invoke_result_nocvref_t( - std::move(value())) - : detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), std::move(error()))); - } + nsel_constexpr14 expected> + transform_error(F &&f) && + { + return has_value() + ? expected>(in_place, std::move(**this)) + : make_unexpected(detail::invoke(std::forward(f), std::move(error()))); + } - template >::value - &&std::is_same::value_type, - value_type>::value && - std::is_constructible::value)> - nsel_constexpr detail::invoke_result_nocvref_t - or_else(F &&f) const && { - return has_value() - ? detail::invoke_result_nocvref_t( - std::move(value())) - : detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), std::move(error()))); - } + template>::value + &&std::is_constructible::value)> + nsel_constexpr expected> + transform_error(F &&f) const && + { + return has_value() + ? expected>( + in_place, std::move(**this)) + : make_unexpected(detail::invoke(std::forward(f), std::move(error()))); + } #endif +#endif// nsel_P2505R >= 3 + // unwrap() - template ::value && - !std::is_void< - detail::transform_invoke_result_t>::value && - detail::valid_expected_value_type< - detail::transform_invoke_result_t>::value)> - nsel_constexpr14 - expected, error_type> - transform(F &&f) & { - return has_value() - ? expected, - error_type>( - detail::invoke(std::forward(f), **this)) - : make_unexpected(error()); - } + // template + // constexpr expected expected,E>::unwrap() const&; - template ::value &&std::is_void< - detail::transform_invoke_result_t>::value)> - nsel_constexpr14 expected transform(F &&f) & { - return has_value() ? (detail::invoke(std::forward(f), **this), - expected()) - : make_unexpected(error()); - } + // template + // constexpr expected expected::unwrap() const&; - template ::value && - !std::is_void< - detail::transform_invoke_result_t>::value && - detail::valid_expected_value_type< - detail::transform_invoke_result_t>::value)> - nsel_constexpr - expected, - error_type> - transform(F &&f) const & { - return has_value() - ? expected< - detail::transform_invoke_result_t, - error_type>(detail::invoke(std::forward(f), **this)) - : make_unexpected(error()); - } + // template + // expected expected, E>::unwrap() &&; - template ::value - &&std::is_void>::value)> - nsel_constexpr expected transform(F &&f) const & { - return has_value() ? (detail::invoke(std::forward(f), **this), - expected()) - : make_unexpected(error()); - } + // template + // template expected expected::unwrap() &&; -#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - template ::value && - !std::is_void< - detail::transform_invoke_result_t>::value && - detail::valid_expected_value_type< - detail::transform_invoke_result_t>::value)> - nsel_constexpr14 - expected, - error_type> - transform(F &&f) && { - return has_value() - ? expected, - error_type>( - detail::invoke(std::forward(f), std::move(**this))) - : make_unexpected(std::move(error())); - } + // factories - template ::value &&std::is_void< - detail::transform_invoke_result_t>::value)> - nsel_constexpr14 expected transform(F &&f) && { - return has_value() ? (detail::invoke(std::forward(f), **this), - expected()) - : make_unexpected(std::move(error())); - } + // template< typename Ex, typename F> + // expected catch_exception(F&& f); - template ::value && - !std::is_void< - detail::transform_invoke_result_t>::value && - detail::valid_expected_value_type< - detail::transform_invoke_result_t>::value)> - nsel_constexpr - expected, - error_type> - transform(F &&f) const && { - return has_value() ? expected, - error_type>(detail::invoke( - std::forward(f), std::move(**this))) - : make_unexpected(std::move(error())); - } + // template< typename F> + // expected())),E> map(F&& func) ; - template ::value - &&std::is_void>::value)> - nsel_constexpr expected transform(F &&f) const && { - return has_value() ? (detail::invoke(std::forward(f), **this), - expected()) - : make_unexpected(std::move(error())); - } -#endif + // template< typename F> + // 'see below' bind(F&& func); - template >::value - &&std::is_constructible::value)> - nsel_constexpr14 - expected> - transform_error(F &&f) & { - return has_value() - ? expected>( - in_place, **this) - : make_unexpected(detail::invoke(std::forward(f), error())); - } + // template< typename F> + // expected catch_error(F&& f); - template >::value - &&std::is_constructible::value)> - nsel_constexpr - expected> - transform_error(F &&f) const & { - return has_value() - ? expected>(in_place, - **this) - : make_unexpected(detail::invoke(std::forward(f), error())); - } + // template< typename F> + // 'see below' then(F&& func); -#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - template >::value - &&std::is_constructible::value)> - nsel_constexpr14 - expected> - transform_error(F &&f) && { - return has_value() - ? expected>( - in_place, std::move(**this)) - : make_unexpected( - detail::invoke(std::forward(f), std::move(error()))); - } + private: + detail::storage_t::value && std::is_copy_constructible::value, + std::is_move_constructible::value && std::is_move_constructible::value> + contained; + }; - template >::value - &&std::is_constructible::value)> - nsel_constexpr - expected> - transform_error(F &&f) const && { - return has_value() - ? expected>( - in_place, std::move(**this)) - : make_unexpected( - detail::invoke(std::forward(f), std::move(error()))); - } -#endif -#endif // nsel_P2505R >= 3 - // unwrap() + /// class expected, void specialization - // template - // constexpr expected expected,E>::unwrap() const&; + template + class expected { + private: + template + friend class expected; - // template - // constexpr expected expected::unwrap() const&; + public: + using value_type = void; + using error_type = E; + using unexpected_type = nonstd::unexpected_type; - // template - // expected expected, E>::unwrap() &&; + // x.x.4.1 constructors - // template - // template expected expected::unwrap() &&; + constexpr expected() noexcept : contained(true) {} - // factories + nsel_constexpr14 expected(expected const &other) = default; + nsel_constexpr14 expected(expected &&other) = default; - // template< typename Ex, typename F> - // expected catch_exception(F&& f); + constexpr explicit expected(nonstd_lite_in_place_t(void)) : contained(true) {} - // template< typename F> - // expected())),E> map(F&& func) ; + template::value /*=> explicit */ + )> + nsel_constexpr14 explicit expected(nonstd::unexpected_type const &error) : contained(false) + { + contained.construct_error(E{error.value()}); + } - // template< typename F> - // 'see below' bind(F&& func); + template::value /*=> non-explicit */ + )> + nsel_constexpr14 /*non-explicit*/ + expected(nonstd::unexpected_type const &error) + : contained(false) + { + contained.construct_error(error.value()); + } - // template< typename F> - // expected catch_error(F&& f); + template::value /*=> explicit */ + )> + nsel_constexpr14 explicit expected(nonstd::unexpected_type &&error) : contained(false) + { + contained.construct_error(E{std::move(error.value())}); + } - // template< typename F> - // 'see below' then(F&& func); + template::value /*=> non-explicit */ + )> + nsel_constexpr14 /*non-explicit*/ + expected(nonstd::unexpected_type &&error) + : contained(false) + { + contained.construct_error(std::move(error.value())); + } - private: - detail::storage_t::value && - std::is_copy_constructible::value, - std::is_move_constructible::value && - std::is_move_constructible::value> - contained; - }; + template::value)> + nsel_constexpr14 explicit expected(unexpect_t, Args &&...args) : contained(false) + { + contained.emplace_error(std::forward(args)...); + } - /// class expected, void specialization + template< + typename U, + typename... Args nsel_REQUIRES_T(std::is_constructible, Args &&...>::value)> + nsel_constexpr14 explicit expected(unexpect_t, std::initializer_list il, Args &&...args) : contained(false) + { + contained.emplace_error(il, std::forward(args)...); + } - template class expected { - private: - template friend class expected; + // destructor - public: - using value_type = void; - using error_type = E; - using unexpected_type = nonstd::unexpected_type; + ~expected() + { + if (!has_value()) { contained.destruct_error(); } + } - // x.x.4.1 constructors + // x.x.4.3 assignment - constexpr expected() noexcept : contained(true) {} + expected &operator=(expected const &other) + { + expected(other).swap(*this); + return *this; + } - nsel_constexpr14 expected(expected const &other) = default; - nsel_constexpr14 expected(expected &&other) = default; + expected &operator=(expected &&other) noexcept(std::is_nothrow_move_assignable::value + && std::is_nothrow_move_constructible::value) + { + expected(std::move(other)).swap(*this); + return *this; + } - constexpr explicit expected(nonstd_lite_in_place_t(void)) - : contained(true) {} + void emplace() { expected().swap(*this); } - template ::value /*=> explicit */ - )> - nsel_constexpr14 explicit expected(nonstd::unexpected_type const &error) - : contained(false) { - contained.construct_error(E{error.value()}); - } + // x.x.4.4 swap - template ::value /*=> non-explicit */ - )> - nsel_constexpr14 /*non-explicit*/ - expected(nonstd::unexpected_type const &error) - : contained(false) { - contained.construct_error(error.value()); - } + template + nsel_REQUIRES_R(void, std17::is_swappable::value &&std::is_move_constructible::value) + swap(expected &other) noexcept(std::is_nothrow_move_constructible::value + && std17::is_nothrow_swappable::value) + { + using std::swap; - template ::value /*=> explicit */ - )> - nsel_constexpr14 explicit expected(nonstd::unexpected_type &&error) - : contained(false) { - contained.construct_error(E{std::move(error.value())}); - } + if (!bool(*this) && !bool(other)) { + swap(contained.error(), other.contained.error()); + } else if (bool(*this) && !bool(other)) { + contained.construct_error(std::move(other.error())); + bool has_value = contained.has_value(); + bool other_has_value = other.has_value(); + other.contained.set_has_value(has_value); + contained.set_has_value(other_has_value); + } else if (!bool(*this) && bool(other)) { + other.swap(*this); + } + } - template ::value /*=> non-explicit */ - )> - nsel_constexpr14 /*non-explicit*/ - expected(nonstd::unexpected_type &&error) - : contained(false) { - contained.construct_error(std::move(error.value())); - } + // x.x.4.5 observers - template ::value)> - nsel_constexpr14 explicit expected(unexpect_t, Args &&...args) - : contained(false) { - contained.emplace_error(std::forward(args)...); - } + constexpr explicit operator bool() const noexcept { return has_value(); } - template , - Args &&...>::value)> - nsel_constexpr14 explicit expected(unexpect_t, std::initializer_list il, - Args &&...args) - : contained(false) { - contained.emplace_error(il, std::forward(args)...); - } + constexpr bool has_value() const noexcept { return contained.has_value(); } - // destructor + void value() const + { + if (!has_value()) { error_traits::rethrow(contained.error()); } + } - ~expected() { - if (!has_value()) { - contained.destruct_error(); - } - } + constexpr error_type const &error() const & { return assert(!has_value()), contained.error(); } - // x.x.4.3 assignment - - expected &operator=(expected const &other) { - expected(other).swap(*this); - return *this; - } - - expected &operator=(expected &&other) noexcept( - std::is_nothrow_move_assignable::value && - std::is_nothrow_move_constructible::value) { - expected(std::move(other)).swap(*this); - return *this; - } - - void emplace() { expected().swap(*this); } - - // x.x.4.4 swap - - template - nsel_REQUIRES_R( - void, - std17::is_swappable::value &&std::is_move_constructible::value) - swap(expected &other) noexcept( - std::is_nothrow_move_constructible::value && - std17::is_nothrow_swappable::value) { - using std::swap; - - if (!bool(*this) && !bool(other)) { - swap(contained.error(), other.contained.error()); - } else if (bool(*this) && !bool(other)) { - contained.construct_error(std::move(other.error())); - bool has_value = contained.has_value(); - bool other_has_value = other.has_value(); - other.contained.set_has_value(has_value); - contained.set_has_value(other_has_value); - } else if (!bool(*this) && bool(other)) { - other.swap(*this); - } - } - - // x.x.4.5 observers - - constexpr explicit operator bool() const noexcept { return has_value(); } - - constexpr bool has_value() const noexcept { return contained.has_value(); } - - void value() const { - if (!has_value()) { - error_traits::rethrow(contained.error()); - } - } - - constexpr error_type const &error() const & { - return assert(!has_value()), contained.error(); - } - - error_type &error() & { return assert(!has_value()), contained.error(); } + error_type &error() & { return assert(!has_value()), contained.error(); } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - constexpr error_type const &&error() const && { - return std::move((assert(!has_value()), contained.error())); - } + constexpr error_type const &&error() const && { return std::move((assert(!has_value()), contained.error())); } - error_type &&error() && { - return std::move((assert(!has_value()), contained.error())); - } + error_type &&error() && { return std::move((assert(!has_value()), contained.error())); } #endif - constexpr unexpected_type get_unexpected() const { - return make_unexpected(contained.error()); - } + constexpr unexpected_type get_unexpected() const { return make_unexpected(contained.error()); } - template bool has_exception() const { - using ContainedEx = typename std::remove_reference< - decltype(get_unexpected().value())>::type; - return !has_value() && std::is_base_of::value; - } + template + bool has_exception() const + { + using ContainedEx = typename std::remove_reference::type; + return !has_value() && std::is_base_of::value; + } #if nsel_P2505R >= 4 - template < - typename G = E nsel_REQUIRES_T(std::is_copy_constructible::value - &&std::is_convertible::value)> - nsel_constexpr error_type error_or(G &&e) const & { - return has_value() ? static_cast(std::forward(e)) - : contained.error(); - } + template< + typename G = E nsel_REQUIRES_T(std::is_copy_constructible::value &&std::is_convertible::value)> + nsel_constexpr error_type error_or(G &&e) const & + { + return has_value() ? static_cast(std::forward(e)) : contained.error(); + } - template < - typename G = E nsel_REQUIRES_T(std::is_move_constructible::value - &&std::is_convertible::value)> - nsel_constexpr14 error_type error_or(G &&e) && { - return has_value() ? static_cast(std::forward(e)) - : std::move(contained.error()); - } -#endif // nsel_P2505R >= 4 + template< + typename G = E nsel_REQUIRES_T(std::is_move_constructible::value &&std::is_convertible::value)> + nsel_constexpr14 error_type error_or(G &&e) && + { + return has_value() ? static_cast(std::forward(e)) : std::move(contained.error()); + } +#endif// nsel_P2505R >= 4 #if nsel_P2505R >= 3 - // Monadic operations (P2505) - template >::value &&std:: - is_same::error_type, - error_type>::value - &&std::is_constructible::value)> - nsel_constexpr14 detail::invoke_result_nocvref_t and_then(F &&f) & { - return has_value() - ? detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f))) - : detail::invoke_result_nocvref_t(unexpect, error()); - } + // Monadic operations (P2505) + template>::value + &&std::is_same::error_type, error_type>::value + &&std::is_constructible::value)> + nsel_constexpr14 detail::invoke_result_nocvref_t and_then(F &&f) & + { + return has_value() ? detail::invoke_result_nocvref_t(detail::invoke(std::forward(f))) + : detail::invoke_result_nocvref_t(unexpect, error()); + } - template >::value &&std:: - is_same::error_type, - error_type>::value - &&std::is_constructible::value)> - nsel_constexpr detail::invoke_result_nocvref_t and_then(F &&f) const & { - return has_value() - ? detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f))) - : detail::invoke_result_nocvref_t(unexpect, error()); - } + template>::value + &&std::is_same::error_type, error_type>::value + &&std::is_constructible::value)> + nsel_constexpr detail::invoke_result_nocvref_t and_then(F &&f) const & + { + return has_value() ? detail::invoke_result_nocvref_t(detail::invoke(std::forward(f))) + : detail::invoke_result_nocvref_t(unexpect, error()); + } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - template >::value &&std:: - is_same::error_type, - error_type>::value - &&std::is_constructible::value)> - nsel_constexpr14 detail::invoke_result_nocvref_t and_then(F &&f) && { - return has_value() ? detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f))) - : detail::invoke_result_nocvref_t( - unexpect, std::move(error())); - } + template>::value + &&std::is_same::error_type, error_type>::value + &&std::is_constructible::value)> + nsel_constexpr14 detail::invoke_result_nocvref_t and_then(F &&f) && + { + return has_value() ? detail::invoke_result_nocvref_t(detail::invoke(std::forward(f))) + : detail::invoke_result_nocvref_t(unexpect, std::move(error())); + } - template >::value &&std:: - is_same::error_type, - error_type>::value && - std::is_constructible::value)> - nsel_constexpr detail::invoke_result_nocvref_t and_then(F &&f) const && { - return has_value() ? detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f))) - : detail::invoke_result_nocvref_t( - unexpect, std::move(error())); - } + template>::value + &&std::is_same::error_type, error_type>::value + &&std::is_constructible::value)> + nsel_constexpr detail::invoke_result_nocvref_t and_then(F &&f) const && + { + return has_value() ? detail::invoke_result_nocvref_t(detail::invoke(std::forward(f))) + : detail::invoke_result_nocvref_t(unexpect, std::move(error())); + } #endif - template >:: - value &&std::is_void::value_type>::value)> - nsel_constexpr14 detail::invoke_result_nocvref_t - or_else(F &&f) & { - return has_value() ? detail::invoke_result_nocvref_t() - : detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), error())); - } + template>::value + &&std::is_void::value_type>::value)> + nsel_constexpr14 detail::invoke_result_nocvref_t or_else(F &&f) & + { + return has_value() + ? detail::invoke_result_nocvref_t() + : detail::invoke_result_nocvref_t(detail::invoke(std::forward(f), error())); + } - template >::value - &&std::is_void::value_type>::value)> - nsel_constexpr detail::invoke_result_nocvref_t - or_else(F &&f) const & { - return has_value() - ? detail::invoke_result_nocvref_t() - : detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), error())); - } + template>::value + &&std::is_void::value_type>::value)> + nsel_constexpr detail::invoke_result_nocvref_t or_else(F &&f) const & + { + return has_value() + ? detail::invoke_result_nocvref_t() + : detail::invoke_result_nocvref_t(detail::invoke(std::forward(f), error())); + } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - template >:: - value &&std::is_void::value_type>::value)> - nsel_constexpr14 detail::invoke_result_nocvref_t - or_else(F &&f) && { - return has_value() - ? detail::invoke_result_nocvref_t() - : detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), std::move(error()))); - } + template>::value + &&std::is_void::value_type>::value)> + nsel_constexpr14 detail::invoke_result_nocvref_t or_else(F &&f) && + { + return has_value() + ? detail::invoke_result_nocvref_t() + : detail::invoke_result_nocvref_t( + detail::invoke(std::forward(f), std::move(error()))); + } - template >::value - &&std::is_void::value_type>::value)> - nsel_constexpr detail::invoke_result_nocvref_t - or_else(F &&f) const && { - return has_value() - ? detail::invoke_result_nocvref_t() - : detail::invoke_result_nocvref_t( - detail::invoke(std::forward(f), std::move(error()))); - } + template>::value + &&std::is_void::value_type>::value)> + nsel_constexpr detail::invoke_result_nocvref_t or_else(F &&f) const && + { + return has_value() + ? detail::invoke_result_nocvref_t() + : detail::invoke_result_nocvref_t( + detail::invoke(std::forward(f), std::move(error()))); + } #endif - template ::value && - !std::is_void>::value)> - nsel_constexpr14 expected, error_type> - transform(F &&f) & { - return has_value() - ? expected, error_type>( - detail::invoke(std::forward(f))) - : make_unexpected(error()); - } + template::value + && !std::is_void>::value)> + nsel_constexpr14 expected, error_type> transform(F &&f) & + { + return has_value() + ? expected, error_type>(detail::invoke(std::forward(f))) + : make_unexpected(error()); + } - template ::value - &&std::is_void>::value)> - nsel_constexpr14 expected transform(F &&f) & { - return has_value() ? (detail::invoke(std::forward(f)), - expected()) - : make_unexpected(error()); - } + template::value + &&std::is_void>::value)> + nsel_constexpr14 expected transform(F &&f) & + { + return has_value() ? (detail::invoke(std::forward(f)), expected()) + : make_unexpected(error()); + } - template ::value && - !std::is_void>::value)> - nsel_constexpr expected, error_type> - transform(F &&f) const & { - return has_value() - ? expected, error_type>( - detail::invoke(std::forward(f))) - : make_unexpected(error()); - } + template::value + && !std::is_void>::value)> + nsel_constexpr expected, error_type> transform(F &&f) const & + { + return has_value() + ? expected, error_type>(detail::invoke(std::forward(f))) + : make_unexpected(error()); + } - template ::value - &&std::is_void>::value)> - nsel_constexpr expected transform(F &&f) const & { - return has_value() ? (detail::invoke(std::forward(f)), - expected()) - : make_unexpected(error()); - } + template::value + &&std::is_void>::value)> + nsel_constexpr expected transform(F &&f) const & + { + return has_value() ? (detail::invoke(std::forward(f)), expected()) + : make_unexpected(error()); + } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - template ::value && - !std::is_void>::value)> - nsel_constexpr14 expected, error_type> - transform(F &&f) && { - return has_value() - ? expected, error_type>( - detail::invoke(std::forward(f))) - : make_unexpected(error()); - } + template::value + && !std::is_void>::value)> + nsel_constexpr14 expected, error_type> transform(F &&f) && + { + return has_value() + ? expected, error_type>(detail::invoke(std::forward(f))) + : make_unexpected(error()); + } - template ::value - &&std::is_void>::value)> - nsel_constexpr14 expected transform(F &&f) && { - return has_value() ? (detail::invoke(std::forward(f)), - expected()) - : make_unexpected(error()); - } + template::value + &&std::is_void>::value)> + nsel_constexpr14 expected transform(F &&f) && + { + return has_value() ? (detail::invoke(std::forward(f)), expected()) + : make_unexpected(error()); + } - template ::value && - !std::is_void>::value)> - nsel_constexpr expected, error_type> - transform(F &&f) const && { - return has_value() - ? expected, error_type>( - detail::invoke(std::forward(f))) - : make_unexpected(error()); - } + template::value + && !std::is_void>::value)> + nsel_constexpr expected, error_type> transform(F &&f) const && + { + return has_value() + ? expected, error_type>(detail::invoke(std::forward(f))) + : make_unexpected(error()); + } - template ::value - &&std::is_void>::value)> - nsel_constexpr expected transform(F &&f) const && { - return has_value() ? (detail::invoke(std::forward(f)), - expected()) - : make_unexpected(error()); - } + template::value + &&std::is_void>::value)> + nsel_constexpr expected transform(F &&f) const && + { + return has_value() ? (detail::invoke(std::forward(f)), expected()) + : make_unexpected(error()); + } #endif - template >::value)> - nsel_constexpr14 - expected> - transform_error(F &&f) & { - return has_value() - ? expected>() - : make_unexpected(detail::invoke(std::forward(f), error())); - } + template>::value)> + nsel_constexpr14 expected> transform_error(F &&f) & + { + return has_value() ? expected>() + : make_unexpected(detail::invoke(std::forward(f), error())); + } - template >::value)> - nsel_constexpr - expected> - transform_error(F &&f) const & { - return has_value() - ? expected>() - : make_unexpected(detail::invoke(std::forward(f), error())); - } + template>::value)> + nsel_constexpr expected> + transform_error(F &&f) const & + { + return has_value() ? expected>() + : make_unexpected(detail::invoke(std::forward(f), error())); + } #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 - template >::value)> - nsel_constexpr14 - expected> - transform_error(F &&f) && { - return has_value() ? expected>() - : make_unexpected(detail::invoke(std::forward(f), - std::move(error()))); - } + template>::value)> + nsel_constexpr14 expected> transform_error(F &&f) && + { + return has_value() ? expected>() + : make_unexpected(detail::invoke(std::forward(f), std::move(error()))); + } - template >::value)> - nsel_constexpr - expected> - transform_error(F &&f) const && { - return has_value() ? expected>() - : make_unexpected(detail::invoke(std::forward(f), - std::move(error()))); - } + template>::value)> + nsel_constexpr expected> + transform_error(F &&f) const && + { + return has_value() ? expected>() + : make_unexpected(detail::invoke(std::forward(f), std::move(error()))); + } #endif -#endif // nsel_P2505R >= 3 +#endif// nsel_P2505R >= 3 - // template constexpr 'see below' unwrap() const&; - // - // template 'see below' unwrap() &&; + // template constexpr 'see below' unwrap() const&; + // + // template 'see below' unwrap() &&; - // factories + // factories - // template< typename Ex, typename F> - // expected catch_exception(F&& f); - // - // template< typename F> - // expected map(F&& func) ; - // - // template< typename F> - // 'see below' bind(F&& func) ; - // - // template< typename F> - // expected catch_error(F&& f); - // - // template< typename F> - // 'see below' then(F&& func); + // template< typename Ex, typename F> + // expected catch_exception(F&& f); + // + // template< typename F> + // expected map(F&& func) ; + // + // template< typename F> + // 'see below' bind(F&& func) ; + // + // template< typename F> + // expected catch_error(F&& f); + // + // template< typename F> + // 'see below' then(F&& func); - private: - detail::storage_t::value, - std::is_move_constructible::value> - contained; - }; + private: + detail::storage_t::value, std::is_move_constructible::value> + contained; + }; - // x.x.4.6 expected<>: comparison operators + // x.x.4.6 expected<>: comparison operators - template ::value && - !std::is_void::value)> - constexpr bool operator==(expected const &x, - expected const &y) { - return bool(x) != bool(y) ? false - : bool(x) ? *x == *y - : x.error() == y.error(); - } + template::value && !std::is_void::value)> + constexpr bool operator==(expected const &x, expected const &y) + { + return bool(x) != bool(y) ? false : bool(x) ? *x == *y : x.error() == y.error(); + } - template ::value &&std::is_void::value)> - constexpr bool operator==(expected const &x, - expected const &y) { - return bool(x) != bool(y) - ? false - : bool(x) || static_cast(x.error() == y.error()); - } + template::value &&std::is_void::value)> + constexpr bool operator==(expected const &x, expected const &y) + { + return bool(x) != bool(y) ? false : bool(x) || static_cast(x.error() == y.error()); + } - template - constexpr bool operator!=(expected const &x, - expected const &y) { - return !(x == y); - } + template + constexpr bool operator!=(expected const &x, expected const &y) + { + return !(x == y); + } #if nsel_P0323R <= 2 - template - constexpr bool operator<(expected const &x, expected const &y) { - return (!y) ? false : (!x) ? true : *x < *y; - } + template + constexpr bool operator<(expected const &x, expected const &y) + { + return (!y) ? false : (!x) ? true : *x < *y; + } - template - constexpr bool operator>(expected const &x, expected const &y) { - return (y < x); - } + template + constexpr bool operator>(expected const &x, expected const &y) + { + return (y < x); + } - template - constexpr bool operator<=(expected const &x, expected const &y) { - return !(y < x); - } + template + constexpr bool operator<=(expected const &x, expected const &y) + { + return !(y < x); + } - template - constexpr bool operator>=(expected const &x, expected const &y) { - return !(x < y); - } + template + constexpr bool operator>=(expected const &x, expected const &y) + { + return !(x < y); + } #endif - // x.x.4.7 expected: comparison with T + // x.x.4.7 expected: comparison with T - template ::value)> - constexpr bool operator==(expected const &x, T2 const &v) { - return bool(x) ? *x == v : false; - } + template::value)> + constexpr bool operator==(expected const &x, T2 const &v) + { + return bool(x) ? *x == v : false; + } - template ::value)> - constexpr bool operator==(T2 const &v, expected const &x) { - return bool(x) ? v == *x : false; - } + template::value)> + constexpr bool operator==(T2 const &v, expected const &x) + { + return bool(x) ? v == *x : false; + } - template - constexpr bool operator!=(expected const &x, T2 const &v) { - return bool(x) ? *x != v : true; - } + template + constexpr bool operator!=(expected const &x, T2 const &v) + { + return bool(x) ? *x != v : true; + } - template - constexpr bool operator!=(T2 const &v, expected const &x) { - return bool(x) ? v != *x : true; - } + template + constexpr bool operator!=(T2 const &v, expected const &x) + { + return bool(x) ? v != *x : true; + } #if nsel_P0323R <= 2 - template - constexpr bool operator<(expected const &x, T const &v) { - return bool(x) ? *x < v : true; - } + template + constexpr bool operator<(expected const &x, T const &v) + { + return bool(x) ? *x < v : true; + } - template - constexpr bool operator<(T const &v, expected const &x) { - return bool(x) ? v < *x : false; - } + template + constexpr bool operator<(T const &v, expected const &x) + { + return bool(x) ? v < *x : false; + } - template - constexpr bool operator>(T const &v, expected const &x) { - return bool(x) ? *x < v : false; - } + template + constexpr bool operator>(T const &v, expected const &x) + { + return bool(x) ? *x < v : false; + } - template - constexpr bool operator>(expected const &x, T const &v) { - return bool(x) ? v < *x : false; - } + template + constexpr bool operator>(expected const &x, T const &v) + { + return bool(x) ? v < *x : false; + } - template - constexpr bool operator<=(T const &v, expected const &x) { - return bool(x) ? !(*x < v) : false; - } + template + constexpr bool operator<=(T const &v, expected const &x) + { + return bool(x) ? !(*x < v) : false; + } - template - constexpr bool operator<=(expected const &x, T const &v) { - return bool(x) ? !(v < *x) : true; - } + template + constexpr bool operator<=(expected const &x, T const &v) + { + return bool(x) ? !(v < *x) : true; + } - template - constexpr bool operator>=(expected const &x, T const &v) { - return bool(x) ? !(*x < v) : false; - } + template + constexpr bool operator>=(expected const &x, T const &v) + { + return bool(x) ? !(*x < v) : false; + } - template - constexpr bool operator>=(T const &v, expected const &x) { - return bool(x) ? !(v < *x) : true; - } + template + constexpr bool operator>=(T const &v, expected const &x) + { + return bool(x) ? !(v < *x) : true; + } -#endif // nsel_P0323R +#endif// nsel_P0323R - // x.x.4.8 expected: comparison with unexpected_type + // x.x.4.8 expected: comparison with unexpected_type - template - constexpr bool operator==(expected const &x, - unexpected_type const &u) { - return (!x) ? x.get_unexpected() == u : false; - } + template + constexpr bool operator==(expected const &x, unexpected_type const &u) + { + return (!x) ? x.get_unexpected() == u : false; + } - template - constexpr bool operator==(unexpected_type const &u, - expected const &x) { - return (x == u); - } + template + constexpr bool operator==(unexpected_type const &u, expected const &x) + { + return (x == u); + } - template - constexpr bool operator!=(expected const &x, - unexpected_type const &u) { - return !(x == u); - } + template + constexpr bool operator!=(expected const &x, unexpected_type const &u) + { + return !(x == u); + } - template - constexpr bool operator!=(unexpected_type const &u, - expected const &x) { - return !(x == u); - } + template + constexpr bool operator!=(unexpected_type const &u, expected const &x) + { + return !(x == u); + } #if nsel_P0323R <= 2 - template - constexpr bool operator<(expected const &x, - unexpected_type const &u) { - return (!x) ? (x.get_unexpected() < u) : false; - } + template + constexpr bool operator<(expected const &x, unexpected_type const &u) + { + return (!x) ? (x.get_unexpected() < u) : false; + } - template - constexpr bool operator<(unexpected_type const &u, - expected const &x) { - return (!x) ? (u < x.get_unexpected()) : true; - } + template + constexpr bool operator<(unexpected_type const &u, expected const &x) + { + return (!x) ? (u < x.get_unexpected()) : true; + } - template - constexpr bool operator>(expected const &x, - unexpected_type const &u) { - return (u < x); - } + template + constexpr bool operator>(expected const &x, unexpected_type const &u) + { + return (u < x); + } - template - constexpr bool operator>(unexpected_type const &u, - expected const &x) { - return (x < u); - } + template + constexpr bool operator>(unexpected_type const &u, expected const &x) + { + return (x < u); + } - template - constexpr bool operator<=(expected const &x, - unexpected_type const &u) { - return !(u < x); - } + template + constexpr bool operator<=(expected const &x, unexpected_type const &u) + { + return !(u < x); + } - template - constexpr bool operator<=(unexpected_type const &u, - expected const &x) { - return !(x < u); - } + template + constexpr bool operator<=(unexpected_type const &u, expected const &x) + { + return !(x < u); + } - template - constexpr bool operator>=(expected const &x, - unexpected_type const &u) { - return !(u > x); - } + template + constexpr bool operator>=(expected const &x, unexpected_type const &u) + { + return !(u > x); + } - template - constexpr bool operator>=(unexpected_type const &u, - expected const &x) { - return !(x > u); - } + template + constexpr bool operator>=(unexpected_type const &u, expected const &x) + { + return !(x > u); + } -#endif // nsel_P0323R +#endif// nsel_P0323R - /// x.x.x Specialized algorithms + /// x.x.x Specialized algorithms - template ::value || - std::is_move_constructible::value) && - std::is_move_constructible::value && - std17::is_swappable::value && - std17::is_swappable::value)> - void swap(expected &x, - expected &y) noexcept(noexcept(x.swap(y))) { - x.swap(y); - } + template::value || std::is_move_constructible::value) + && std::is_move_constructible::value && std17::is_swappable::value + && std17::is_swappable::value)> + void swap(expected &x, expected &y) noexcept(noexcept(x.swap(y))) + { + x.swap(y); + } #if nsel_P0323R <= 3 - template - constexpr auto - make_expected(T &&v) -> expected::type> { - return expected::type>(std::forward(v)); - } - - // expected specialization: - - auto inline make_expected() -> expected { - return expected(in_place); - } - - template - constexpr auto make_expected_from_current_exception() -> expected { - return expected(make_unexpected_from_current_exception()); - } - - template - auto make_expected_from_exception(std::exception_ptr v) -> expected { - return expected(unexpected_type( - std::forward(v))); - } - - template - constexpr auto - make_expected_from_error(E e) -> expected::type> { - return expected::type>(make_unexpected(e)); - } - - template ::type, void>::value)> - /*nsel_constexpr14*/ - auto - make_expected_from_call(F f) -> expected::type> { - try { - return make_expected(f()); - } catch (...) { - return make_unexpected_from_current_exception(); + template + constexpr auto make_expected(T &&v) -> expected::type> + { + return expected::type>(std::forward(v)); } - } - template ::type, void>::value)> - /*nsel_constexpr14*/ - auto make_expected_from_call(F f) -> expected { - try { - f(); - return make_expected(); - } catch (...) { - return make_unexpected_from_current_exception(); + // expected specialization: + + auto inline make_expected() -> expected { return expected(in_place); } + + template + constexpr auto make_expected_from_current_exception() -> expected + { + return expected(make_unexpected_from_current_exception()); } - } -#endif // nsel_P0323R + template + auto make_expected_from_exception(std::exception_ptr v) -> expected + { + return expected(unexpected_type(std::forward(v))); + } - } // namespace expected_lite + template + constexpr auto make_expected_from_error(E e) -> expected::type> + { + return expected::type>(make_unexpected(e)); + } - using namespace expected_lite; + template::type, void>::value)> + /*nsel_constexpr14*/ + auto make_expected_from_call(F f) -> expected::type> + { + try { + return make_expected(f()); + } catch (...) { + return make_unexpected_from_current_exception(); + } + } - // using expected_lite::expected; - // using ... + template::type, void>::value)> + /*nsel_constexpr14*/ + auto make_expected_from_call(F f) -> expected + { + try { + f(); + return make_expected(); + } catch (...) { + return make_unexpected_from_current_exception(); + } + } -} // namespace nonstd +#endif// nsel_P0323R + + }// namespace expected_lite + + using namespace expected_lite; + + // using expected_lite::expected; + // using ... + +}// namespace nonstd namespace std { // expected: hash support -template struct hash> { - using result_type = std::size_t; - using argument_type = nonstd::expected; +template +struct hash> { + using result_type = std::size_t; + using argument_type = nonstd::expected; - constexpr result_type operator()(argument_type const &arg) const { - return arg ? std::hash{}(*arg) : result_type{}; - } + constexpr result_type operator()(argument_type const &arg) const + { + return arg ? std::hash{}(*arg) : result_type{}; + } }; // TBD - ?? remove? see spec. -template struct hash> { - using result_type = std::size_t; - using argument_type = nonstd::expected; +template +struct hash> { + using result_type = std::size_t; + using argument_type = nonstd::expected; - constexpr result_type operator()(argument_type const &arg) const { - return arg ? std::hash{}(*arg) : result_type{}; - } + constexpr result_type operator()(argument_type const &arg) const + { + return arg ? std::hash{}(*arg) : result_type{}; + } }; // TBD - implement @@ -3039,19 +2868,21 @@ template struct hash> { // otherwise it evaluates to an unspecified value if E is exception_ptr or // a combination of hashing false and hash()(e.error()). -template struct hash> {}; +template +struct hash> {}; -} // namespace std +}// namespace std namespace nonstd { // void unexpected() is deprecated && removed in C++17 #if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141 -template using unexpected = unexpected_type; +template +using unexpected = unexpected_type; #endif -} // namespace nonstd +}// namespace nonstd #undef nsel_REQUIRES #undef nsel_REQUIRES_0 @@ -3059,9 +2890,9 @@ template using unexpected = unexpected_type; nsel_RESTORE_WARNINGS() -#endif // nsel_USES_STD_EXPECTED +#endif// nsel_USES_STD_EXPECTED namespace std { using namespace nonstd; } -#endif // NONSTD_EXPECTED_LITE_HPP +#endif// NONSTD_EXPECTED_LITE_HPP diff --git a/tile/base/exposed_var.cc b/tile/base/exposed_var.cc index cd032e2..a33bc7f 100644 --- a/tile/base/exposed_var.cc +++ b/tile/base/exposed_var.cc @@ -8,293 +8,294 @@ namespace tile { // namespace exposed_var { namespace { -#define CHECK_PATH(path) \ - TILE_CHECK((path).size() <= 1 || (path).back() != '/', \ - "Invalid path: [{}].", path); \ - TILE_CHECK((path).find("//") == tile::Slice::npos, "Invalid path: [{}].", \ - path); +#define CHECK_PATH(path) \ + TILE_CHECK((path).size() <= 1 || (path).back() != '/', "Invalid path: [{}].", path); \ + TILE_CHECK((path).find("//") == tile::Slice::npos, "Invalid path: [{}].", path); -#define CHECK_RELATIVE_PATH(path) \ - CHECK_PATH(path); \ - TILE_CHECK((path).empty() || (path).front() != '/', "Invalid path: [{}].", \ - path); +#define CHECK_RELATIVE_PATH(path) \ + CHECK_PATH(path); \ + TILE_CHECK((path).empty() || (path).front() != '/', "Invalid path: [{}].", path); -#define CHECK_ABSOLUTE_PATH(path) \ - CHECK_PATH(path); \ - TILE_CHECK((path).empty() || (path).front() == '/', "Invalid path: [{}]", \ - path); +#define CHECK_ABSOLUTE_PATH(path) \ + CHECK_PATH(path); \ + TILE_CHECK((path).empty() || (path).front() == '/', "Invalid path: [{}]", path); + +std::pair +SplitFirstPart(Slice path) +{ + auto pos = path.find_first_of('/'); + if (pos == tile::Slice::npos) { + return std::make_pair(path, ""); + } else { + return std::make_pair(path.substr(0, pos), path.substr(pos + 1)); + } +} + +std::pair +SplitLastPart(Slice path) +{ + auto pos = path.find_last_of('/'); + if (pos == tile::Slice::npos) { return std::make_pair("", path); } -std::pair SplitFirstPart(Slice path) { - auto pos = path.find_first_of('/'); - if (pos == tile::Slice::npos) { - return std::make_pair(path, ""); - } else { return std::make_pair(path.substr(0, pos), path.substr(pos + 1)); - } } -std::pair SplitLastPart(Slice path) { - auto pos = path.find_last_of('/'); - if (pos == tile::Slice::npos) { - return std::make_pair("", path); - } +std::string +JoinPath(Slice a, Slice b) +{ + if (EndsWith(b, "/")) { b.RemoveSuffix(1); } - return std::make_pair(path.substr(0, pos), path.substr(pos + 1)); + if (EndsWith(a, "/")) { a.RemoveSuffix(1); } + + if (b.empty()) { return a.ToString(); } + if (a.empty()) { return b.ToString(); } + + return a.ToString() + "/" + b.ToString(); } -std::string JoinPath(Slice a, Slice b) { - if (EndsWith(b, "/")) { - b.RemoveSuffix(1); - } - - if (EndsWith(a, "/")) { - a.RemoveSuffix(1); - } - - if (b.empty()) { - return a.ToString(); - } - if (a.empty()) { - return b.ToString(); - } - - return a.ToString() + "/" + b.ToString(); +std::string +SubstituteEscapedSlashForZero(Slice path) +{ + TILE_CHECK(path.find('\0') == tile::Slice::npos); + return Replace(path, "\\/", '\0'); } -std::string SubstituteEscapedSlashForZero(Slice path) { - TILE_CHECK(path.find('\0') == tile::Slice::npos); - return Replace(path, "\\/", '\0'); +std::string +SubstituteZeroForEscapedSlash(Slice path) +{ + return Replace(path, '\0', "\\/"); } -std::string SubstituteZeroForEscapedSlash(Slice path) { - return Replace(path, '\0', "\\/"); +std::string +UnescapeZeroToPlainSlash(Slice path) +{ + return Replace(path, '\0', '/'); } -std::string UnescapeZeroToPlainSlash(Slice path) { - return Replace(path, '\0', '/'); -} - -} // namespace +}// namespace // } // namespace exposed_var ExposedVarGroup::Handle -ExposedVarGroup::Add(Slice rel_path, std::function value) { +ExposedVarGroup::Add(Slice rel_path, std::function value) +{ - auto real_path = SubstituteEscapedSlashForZero(rel_path); - CHECK_RELATIVE_PATH(rel_path); + auto real_path = SubstituteEscapedSlashForZero(rel_path); + CHECK_RELATIVE_PATH(rel_path); - auto path_and_name = SplitLastPart(real_path); - auto name = path_and_name.second.ToString(); + auto path_and_name = SplitLastPart(real_path); + auto name = path_and_name.second.ToString(); - auto moved_func = tile::MakeMoveOnCopy(value); - return CreateUpto(path_and_name.first) - ->AddDirect( - name, - [name, moved_func](Slice expected) -> std::optional { + auto moved_func = tile::MakeMoveOnCopy(value); + return CreateUpto(path_and_name.first) + ->AddDirect(name, [name, moved_func](Slice expected) -> std::optional { auto jsv = moved_func.Ref()(); - if (expected.empty()) { - return jsv; - } + if (expected.empty()) { return jsv; } - auto real_path = SubstituteEscapedSlashForZero(expected); + auto real_path = SubstituteEscapedSlashForZero(expected); Json::Value *ptr = &jsv; - auto pieces = Split(real_path, '/'); + auto pieces = Split(real_path, '/'); for (auto &&e : pieces) { - auto unescaped = UnescapeZeroToPlainSlash({e.data(), e.size()}); - if (ptr->isObject()) { - if (ptr->isMember(unescaped)) { - ptr = &(*ptr)[unescaped]; + auto unescaped = UnescapeZeroToPlainSlash({e.data(), e.size()}); + if (ptr->isObject()) { + if (ptr->isMember(unescaped)) { + ptr = &(*ptr)[unescaped]; + } else { + return {}; + } + } else if (ptr->isArray()) { + auto index = TryParse(unescaped); + if (index && *index < ptr->size()) { + ptr = &(*ptr)[static_cast(*index)]; + } else { + return {}; + } } else { - return {}; + return {}; } - } else if (ptr->isArray()) { - auto index = TryParse(unescaped); - if (index && *index < ptr->size()) { - ptr = &(*ptr)[static_cast(*index)]; - } else { - return {}; - } - } else { - return {}; - } } return *ptr; - }); + }); } ExposedVarGroup::Handle -ExposedVarGroup::Add(Slice rel_path, ExposedVarDynamicTree *dynamic_tree) { - auto real_path = SubstituteEscapedSlashForZero(rel_path); - CHECK_RELATIVE_PATH(real_path); - auto path_and_name = SplitLastPart(real_path); - auto name = path_and_name.second.ToString(); +ExposedVarGroup::Add(Slice rel_path, ExposedVarDynamicTree *dynamic_tree) +{ + auto real_path = SubstituteEscapedSlashForZero(rel_path); + CHECK_RELATIVE_PATH(real_path); + auto path_and_name = SplitLastPart(real_path); + auto name = path_and_name.second.ToString(); - return CreateUpto(path_and_name.first) - ->AddDirect(name, [dynamic_tree](Slice inner_path) { + return CreateUpto(path_and_name.first)->AddDirect(name, [dynamic_tree](Slice inner_path) { return dynamic_tree->TryGet(inner_path); - }); + }); } -ExposedVarGroup *ExposedVarGroup::FindOrCreate(Slice abs_path) { - auto real_path = SubstituteEscapedSlashForZero(abs_path); - CHECK_ABSOLUTE_PATH(real_path); +ExposedVarGroup * +ExposedVarGroup::FindOrCreate(Slice abs_path) +{ + auto real_path = SubstituteEscapedSlashForZero(abs_path); + CHECK_ABSOLUTE_PATH(real_path); - return Root()->CreateUpto(real_path.substr(1)); + return Root()->CreateUpto(real_path.substr(1)); } -std::optional ExposedVarGroup::TryGet(Slice abs_path) { - auto real_path = SubstituteEscapedSlashForZero(abs_path); - TILE_CHECK(!real_path.empty()); - CHECK_ABSOLUTE_PATH(real_path); - if (real_path == "/") { - return Root()->Dump(); - } +std::optional +ExposedVarGroup::TryGet(Slice abs_path) +{ + auto real_path = SubstituteEscapedSlashForZero(abs_path); + TILE_CHECK(!real_path.empty()); + CHECK_ABSOLUTE_PATH(real_path); - Slice left_path; - auto rel_path = real_path.substr(1); - auto parent = Root()->FindLowest(rel_path, &left_path); + if (real_path == "/") { return Root()->Dump(); } - auto name_and_rest = SplitFirstPart(left_path); - if (name_and_rest.first.empty()) { - return parent->Dump(); - } + Slice left_path; + auto rel_path = real_path.substr(1); + auto parent = Root()->FindLowest(rel_path, &left_path); - auto s = name_and_rest.first.ToString(); - std::lock_guard lk(parent->lock_); - auto iter = parent->leaves_.find(s); - if (iter != parent->leaves_.end()) { - return iter->second(SubstituteZeroForEscapedSlash(name_and_rest.second)); - } else { - auto iter = parent->nodes_.find(s); - if (iter != parent->nodes_.end()) { - return iter->second->Dump(); + auto name_and_rest = SplitFirstPart(left_path); + if (name_and_rest.first.empty()) { return parent->Dump(); } + + auto s = name_and_rest.first.ToString(); + std::lock_guard lk(parent->lock_); + auto iter = parent->leaves_.find(s); + if (iter != parent->leaves_.end()) { + return iter->second(SubstituteZeroForEscapedSlash(name_and_rest.second)); } else { - return {}; + auto iter = parent->nodes_.find(s); + if (iter != parent->nodes_.end()) { + return iter->second->Dump(); + } else { + return {}; + } } - } } -ExposedVarGroup::ExposedVarGroup(std::string abs_path) - : abs_path_(std::move(abs_path)) { - CHECK_ABSOLUTE_PATH(abs_path); +ExposedVarGroup::ExposedVarGroup(std::string abs_path) : abs_path_(std::move(abs_path)) +{ + CHECK_ABSOLUTE_PATH(abs_path); } -ExposedVarGroup *ExposedVarGroup::Root() { - static ExposedVarGroup evg("/"); - return &evg; +ExposedVarGroup * +ExposedVarGroup::Root() +{ + static ExposedVarGroup evg("/"); + return &evg; } -const std::string &ExposedVarGroup::AbsolutePath() const { return abs_path_; } -ExposedVarGroup *ExposedVarGroup::FindLowest(Slice rel_path, Slice *left) { - CHECK_RELATIVE_PATH(rel_path); - auto current = this; +const std::string & +ExposedVarGroup::AbsolutePath() const +{ + return abs_path_; +} - while (!rel_path.empty()) { - auto name_and_rest = SplitFirstPart(rel_path); +ExposedVarGroup * +ExposedVarGroup::FindLowest(Slice rel_path, Slice *left) +{ + CHECK_RELATIVE_PATH(rel_path); + auto current = this; - std::lock_guard lk(current->lock_); - auto iter = current->nodes_.find(name_and_rest.first.ToString()); - if (iter == current->nodes_.end()) { - break; - } else { - current = &*iter->second; + while (!rel_path.empty()) { + auto name_and_rest = SplitFirstPart(rel_path); + + std::lock_guard lk(current->lock_); + auto iter = current->nodes_.find(name_and_rest.first.ToString()); + if (iter == current->nodes_.end()) { + break; + } else { + current = &*iter->second; + } + + rel_path = name_and_rest.second; } - rel_path = name_and_rest.second; - } - - if (left) { - *left = rel_path; - } - return current; + if (left) { *left = rel_path; } + return current; } -ExposedVarGroup *ExposedVarGroup::CreateUpto(Slice rel_path) { - CHECK_RELATIVE_PATH(rel_path); +ExposedVarGroup * +ExposedVarGroup::CreateUpto(Slice rel_path) +{ + CHECK_RELATIVE_PATH(rel_path); - Slice left_path; - auto current = FindLowest(rel_path, &left_path); + Slice left_path; + auto current = FindLowest(rel_path, &left_path); - auto pieces = Split(left_path, '/'); + auto pieces = Split(left_path, '/'); - for (auto &&e : pieces) { - auto s = e.ToString(); + for (auto &&e : pieces) { + auto s = e.ToString(); - std::lock_guard lk(current->lock_); - auto p = JoinPath(current->AbsolutePath(), s); + std::lock_guard lk(current->lock_); + auto p = JoinPath(current->AbsolutePath(), s); - TILE_CHECK( - current->leaves_.find(s) == current->leaves_.end(), - "Path [{}] has already been used: A value is registered at [{}].", - rel_path, p); + TILE_CHECK(current->leaves_.find(s) == current->leaves_.end(), + "Path [{}] has already been used: A value is registered at [{}].", rel_path, p); - TILE_CHECK(current->nodes_.find(s) == current->nodes_.end()); - auto evg = std::unique_ptr(new ExposedVarGroup(p)); - current->nodes_[s] = std::move(evg); - current = &*(current->nodes_[s]); - } + TILE_CHECK(current->nodes_.find(s) == current->nodes_.end()); + auto evg = std::unique_ptr(new ExposedVarGroup(p)); + current->nodes_[s] = std::move(evg); + current = &*(current->nodes_[s]); + } - TILE_CHECK(EndsWith(current->AbsolutePath(), rel_path), "[{}] vs [{}]", - current->AbsolutePath(), rel_path); - return current; + TILE_CHECK(EndsWith(current->AbsolutePath(), rel_path), "[{}] vs [{}]", current->AbsolutePath(), rel_path); + return current; } -ExposedVarGroup::Handle ExposedVarGroup::AddDirect(Slice name, Getter value) { - auto s = name.ToString(); - std::lock_guard lk(lock_); - - TILE_CHECK(leaves_.find(s) == leaves_.end(), - "Value [{}] has already been registered at [{}].", name, - AbsolutePath()); - TILE_CHECK(nodes_.find(s) == nodes_.end(), "Path [{}] has already been used.", - JoinPath(AbsolutePath(), name)); - leaves_[s] = std::move(value); - - return Deferred([this, s] { +ExposedVarGroup::Handle +ExposedVarGroup::AddDirect(Slice name, Getter value) +{ + auto s = name.ToString(); std::lock_guard lk(lock_); - TILE_CHECK_EQ(leaves_.erase(s), 1); - }); + + TILE_CHECK(leaves_.find(s) == leaves_.end(), "Value [{}] has already been registered at [{}].", name, + AbsolutePath()); + TILE_CHECK(nodes_.find(s) == nodes_.end(), "Path [{}] has already been used.", JoinPath(AbsolutePath(), name)); + leaves_[s] = std::move(value); + + return Deferred([this, s] { + std::lock_guard lk(lock_); + TILE_CHECK_EQ(leaves_.erase(s), 1); + }); } -Json::Value ExposedVarGroup::Dump() const { - std::lock_guard lk(lock_); - Json::Value jsv; - for (auto &&node : nodes_) { - jsv[UnescapeZeroToPlainSlash(node.first)] = node.second->Dump(); - } +Json::Value +ExposedVarGroup::Dump() const +{ + std::lock_guard lk(lock_); + Json::Value jsv; + for (auto &&node : nodes_) { jsv[UnescapeZeroToPlainSlash(node.first)] = node.second->Dump(); } - for (auto &&leave : leaves_) { - jsv[UnescapeZeroToPlainSlash(leave.first)] = *leave.second(""); - } + for (auto &&leave : leaves_) { jsv[UnescapeZeroToPlainSlash(leave.first)] = *leave.second(""); } - return jsv; + return jsv; } -ExposedVarDynamicTree::ExposedVarDynamicTree( - Slice rel_path, std::function getter, - ExposedVarGroup *parent) - : getter_(std::move(getter)) { - handle_ = parent->Add(rel_path, this); +ExposedVarDynamicTree::ExposedVarDynamicTree(Slice rel_path, + std::function getter, + ExposedVarGroup *parent) + : getter_(std::move(getter)) +{ + handle_ = parent->Add(rel_path, this); } -std::optional ExposedVarDynamicTree::TryGet(Slice rel_path) const { - auto real_path = SubstituteEscapedSlashForZero(rel_path); - auto jsv = getter_(); - Json::Value *ptr = &jsv; +std::optional +ExposedVarDynamicTree::TryGet(Slice rel_path) const +{ + auto real_path = SubstituteEscapedSlashForZero(rel_path); + auto jsv = getter_(); + Json::Value *ptr = &jsv; - auto pieces = Split(real_path, '/'); - for (auto &&e : pieces) { - auto unescaped = UnescapeZeroToPlainSlash({e.data(), e.size()}); - ptr = &(*ptr)[unescaped]; - } + auto pieces = Split(real_path, '/'); + for (auto &&e : pieces) { + auto unescaped = UnescapeZeroToPlainSlash({e.data(), e.size()}); + ptr = &(*ptr)[unescaped]; + } - if (ptr->isNull()) { - return {}; - } + if (ptr->isNull()) { return {}; } - return *ptr; + return *ptr; } -} // namespace tile +}// namespace tile diff --git a/tile/base/exposed_var.h b/tile/base/exposed_var.h index 85d347c..1c91ec0 100644 --- a/tile/base/exposed_var.h +++ b/tile/base/exposed_var.h @@ -15,179 +15,188 @@ namespace tile { namespace exposed_var { -template -auto ToJsonValue(const T &t) - -> enable_if_t::value, Json::Value> { - return t; +template +auto +ToJsonValue(const T &t) -> enable_if_t::value, Json::Value> +{ + return t; } -template -auto ToJsonValue(const T &t) - -> enable_if_t::value && std::is_unsigned::value, - Json::Value> { - return Json::Value(static_cast(t)); +template +auto +ToJsonValue(const T &t) -> enable_if_t::value && std::is_unsigned::value, Json::Value> +{ + return Json::Value(static_cast(t)); } -template -auto ToJsonValue(const T &t) - -> enable_if_t::value && !std::is_unsigned::value, - Json::Value> { - return Json::Value(static_cast(t)); +template +auto +ToJsonValue(const T &t) -> enable_if_t::value && !std::is_unsigned::value, Json::Value> +{ + return Json::Value(static_cast(t)); } -template -auto ToJsonValue(const T &t) - -> enable_if_t::value || - std::is_same::value || - std::is_same::value || - std::is_same::value, - Json::Value> { - return Json::Value(t); +template +auto +ToJsonValue(const T &t) -> enable_if_t::value || std::is_same::value + || std::is_same::value || std::is_same::value, + Json::Value> +{ + return Json::Value(t); } -template -auto ToJsonValue(const T &t) - -> enable_if_t< - !std::is_integral::value && !std::is_floating_point::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - std::is_same()))>::value, - Json::Value> { - return Json::Value(format_as(t)); +template +auto +ToJsonValue(const T &t) -> enable_if_t::value && !std::is_floating_point::value + && !std::is_same::value + && !std::is_same::value && !std::is_same::value + && std::is_same()))>::value, + Json::Value> +{ + return Json::Value(format_as(t)); } -template Json::Value ToJsonValue(const std::atomic &v) { - return ToJsonValue(v.load(std::memory_order_relaxed)); +template +Json::Value +ToJsonValue(const std::atomic &v) +{ + return ToJsonValue(v.load(std::memory_order_relaxed)); } -} // namespace exposed_var +}// namespace exposed_var class ExposedVarDynamicTree; class ExposedVarGroup { public: - using Handle = Deferred; + using Handle = Deferred; - Handle Add(Slice rel_path, std::function value); - Handle Add(Slice rel_path, ExposedVarDynamicTree *dyanmic_tree); - static ExposedVarGroup *FindOrCreate(Slice abs_path); - static std::optional TryGet(Slice abs_path); + Handle Add(Slice rel_path, std::function value); + Handle Add(Slice rel_path, ExposedVarDynamicTree *dyanmic_tree); + static ExposedVarGroup *FindOrCreate(Slice abs_path); + static std::optional TryGet(Slice abs_path); private: - using Getter = std::function(Slice)>; + using Getter = std::function(Slice)>; - explicit ExposedVarGroup(std::string abs_path); - const std::string &AbsolutePath() const; + explicit ExposedVarGroup(std::string abs_path); + const std::string &AbsolutePath() const; - ExposedVarGroup *FindLowest(Slice rel_path, Slice *left); - ExposedVarGroup *CreateUpto(Slice rel_path); - Handle AddDirect(Slice name, Getter getter); - Json::Value Dump() const; - static ExposedVarGroup *Root(); + ExposedVarGroup *FindLowest(Slice rel_path, Slice *left); + ExposedVarGroup *CreateUpto(Slice rel_path); + Handle AddDirect(Slice name, Getter getter); + Json::Value Dump() const; + static ExposedVarGroup *Root(); private: - std::string abs_path_; - mutable std::mutex lock_; + std::string abs_path_; + mutable std::mutex lock_; - std::unordered_map> nodes_; - std::unordered_map leaves_; + std::unordered_map> nodes_; + std::unordered_map leaves_; }; -template class ExposedVar { +template +class ExposedVar { public: - ExposedVar(Slice rel_path) { - LinkToParent(rel_path, ExposedVarGroup::FindOrCreate("/")); - } + ExposedVar(Slice rel_path) { LinkToParent(rel_path, ExposedVarGroup::FindOrCreate("/")); } - template - ExposedVar(Slice rel_path, U &&initial_value, - ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/")) - : obj_(std::forward(initial_value)) { - LinkToParent(rel_path, parent); - } + template + ExposedVar(Slice rel_path, U &&initial_value, ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/")) + : obj_(std::forward(initial_value)) + { + LinkToParent(rel_path, parent); + } - T *operator->() noexcept { return &obj_; } - T &operator*() noexcept { return obj_; } + T *operator->() noexcept { return &obj_; } + + T &operator*() noexcept { return obj_; } private: - void LinkToParent(Slice rel_path, ExposedVarGroup *parent) { - handle_ = parent->Add(rel_path, - [this] { return exposed_var::ToJsonValue(obj_); }); - } + void LinkToParent(Slice rel_path, ExposedVarGroup *parent) + { + handle_ = parent->Add(rel_path, [this] { return exposed_var::ToJsonValue(obj_); }); + } private: - T obj_{}; - ExposedVarGroup::Handle handle_; + T obj_{}; + ExposedVarGroup::Handle handle_; }; -template class ExposedVarDynamic { +template +class ExposedVarDynamic { public: - ExposedVarDynamic( - Slice rel_path, std::function getter, - ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/")) - : getter_(std::move(getter)) { - handle_ = parent->Add( - rel_path, [this] { return exposed_var::ToJsonValue(getter_()); }); - } + ExposedVarDynamic(Slice rel_path, + std::function getter, + ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/")) + : getter_(std::move(getter)) + { + handle_ = parent->Add(rel_path, [this] { return exposed_var::ToJsonValue(getter_()); }); + } private: - std::function getter_; - ExposedVarGroup::Handle handle_; + std::function getter_; + ExposedVarGroup::Handle handle_; }; class ExposedVarDynamicTree { public: - ExposedVarDynamicTree( - Slice rel_path, std::function getter, - ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/")); + ExposedVarDynamicTree(Slice rel_path, + std::function getter, + ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/")); - std::optional TryGet(Slice rel_path) const; + std::optional TryGet(Slice rel_path) const; private: - std::function getter_; - ExposedVarGroup::Handle handle_; + std::function getter_; + ExposedVarGroup::Handle handle_; }; namespace detail { -template struct IdentityTime { - std::uint64_t operator()(const T &val) const { - return (ReadSteadyClock() - std::chrono::steady_clock::time_point()) / - std::chrono::nanoseconds(1); - } +template +struct IdentityTime { + std::uint64_t operator()(const T &val) const + { + return (ReadSteadyClock() - std::chrono::steady_clock::time_point()) / std::chrono::nanoseconds(1); + } }; -} // namespace detail +}// namespace detail -template > +template> class ExposedMetrics { public: - explicit ExposedMetrics(Slice rel_path) { - LinkToParent(rel_path, ExposedVarGroup::FindOrCreate("/")); - } + explicit ExposedMetrics(Slice rel_path) { LinkToParent(rel_path, ExposedVarGroup::FindOrCreate("/")); } private: - Json::Value ToJsonValue(const T &v) { - Json::Value result; - std::unordered_map m = {{"1s", 1}}; - for (auto &&item : m) { + Json::Value ToJsonValue(const T &v) + { + Json::Value result; + std::unordered_map m = { + {"1s", 1} + }; + for (auto &&item : m) {} } - } - void LinkToParent(Slice rel_path, ExposedVarGroup *parent) { - handle_ = parent->Add(rel_path, [this] { return ToJsonValue(obj_); }); - } + void LinkToParent(Slice rel_path, ExposedVarGroup *parent) + { + handle_ = parent->Add(rel_path, [this] { return ToJsonValue(obj_); }); + } private: - T obj_{}; - ExposedVarGroup::Handle handle_; + T obj_{}; + ExposedVarGroup::Handle handle_; }; -template using ExposedCounter = ExposedVar; -template using ExposedGauge = ExposedVar; -template using ExposedMiner = ExposedVar; -template using ExposedMaxer = ExposedVar; -template using ExposedAverager = ExposedVar; +template +using ExposedCounter = ExposedVar; +template +using ExposedGauge = ExposedVar; +template +using ExposedMiner = ExposedVar; +template +using ExposedMaxer = ExposedVar; +template +using ExposedAverager = ExposedVar; -} // namespace tile +}// namespace tile -#endif // TILE_BASE_EXPOSED_VAR_H +#endif// TILE_BASE_EXPOSED_VAR_H diff --git a/tile/base/exposed_var_test.cc b/tile/base/exposed_var_test.cc index 2c078c7..d1bc6c4 100644 --- a/tile/base/exposed_var_test.cc +++ b/tile/base/exposed_var_test.cc @@ -4,14 +4,19 @@ #include "json/json.h" namespace tile { -ExposedVarGroup *GetFancyGroup() { - return ExposedVarGroup::FindOrCreate("/a/b"); +ExposedVarGroup * +GetFancyGroup() +{ + return ExposedVarGroup::FindOrCreate("/a/b"); } -Json::Value GetTree() { - Json::Value jsv; - jsv["dir"]["sub-dir"]["key"] = 5; - jsv["key"] = "6"; - return jsv; + +Json::Value +GetTree() +{ + Json::Value jsv; + jsv["dir"]["sub-dir"]["key"] = 5; + jsv["key"] = "6"; + return jsv; } ExposedVar v1("v1", 5); @@ -21,18 +26,18 @@ ExposedVar f1("f1", 6.2, ExposedVarGroup::FindOrCreate("/x/y/z")); auto GreatGroup = ExposedVarGroup::FindOrCreate("/a/b"); // `/a/b/ds1` -ExposedVarDynamic - ds1("ds1", [] { return "test_str"; }, GetFancyGroup()); +ExposedVarDynamic ds1("ds1", [] { return "test_str"; }, GetFancyGroup()); -TEST(ExposedVar, Mutate) { - auto opt = ExposedVarGroup::TryGet("/"); - ASSERT_TRUE(opt); - auto &&jsv = *opt; - ASSERT_EQ(5, jsv["v1"].asInt()); - *v1 = 6; - jsv = *ExposedVarGroup::TryGet("/"); - ASSERT_EQ(6, jsv["v1"].asInt()); - *v1 = 5; +TEST(ExposedVar, Mutate) +{ + auto opt = ExposedVarGroup::TryGet("/"); + ASSERT_TRUE(opt); + auto &&jsv = *opt; + ASSERT_EQ(5, jsv["v1"].asInt()); + *v1 = 6; + jsv = *ExposedVarGroup::TryGet("/"); + ASSERT_EQ(6, jsv["v1"].asInt()); + *v1 = 5; } -} // namespace tile +}// namespace tile diff --git a/tile/base/future.h b/tile/base/future.h index 605ef06..a48cb99 100644 --- a/tile/base/future.h +++ b/tile/base/future.h @@ -22,6 +22,6 @@ using future::Split; using future::WhenAll; using future::WhenAny; -} // namespace tile +}// namespace tile -#endif // TILE_BASE_FUTURE_H +#endif// TILE_BASE_FUTURE_H diff --git a/tile/base/future/basic.h b/tile/base/future/basic.h index a07c501..1880930 100644 --- a/tile/base/future/basic.h +++ b/tile/base/future/basic.h @@ -10,54 +10,63 @@ namespace tile { namespace future { -template -struct are_rvalue_refs - : internal::conjunction...> {}; +template +struct are_rvalue_refs : internal::conjunction...> {}; + static_assert(are_rvalue_refs::value, ""); static_assert(!are_rvalue_refs::value, ""); // Rebinds `Ts...` in `TT<....>` to `UT<...>` // Example: // rebind_t, Promise<>> -> Promise -template class To> struct rebind; -template