Commit 21b8e8c5 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/string-view'

parents 99b35153 e3060212
...@@ -104,6 +104,7 @@ set(LIBCAF_CORE_SRCS ...@@ -104,6 +104,7 @@ set(LIBCAF_CORE_SRCS
src/stream_aborter.cpp src/stream_aborter.cpp
src/stream_manager.cpp src/stream_manager.cpp
src/stream_priority.cpp src/stream_priority.cpp
src/string_view.cpp
src/stringification_inspector.cpp src/stringification_inspector.cpp
src/sync_request_bouncer.cpp src/sync_request_bouncer.cpp
src/term.cpp src/term.cpp
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "caf/config_option.hpp" #include "caf/config_option.hpp"
#include "caf/config_option_set.hpp" #include "caf/config_option_set.hpp"
#include "caf/config_value.hpp" #include "caf/config_value.hpp"
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/is_typed_actor.hpp" #include "caf/is_typed_actor.hpp"
#include "caf/named_actor_config.hpp" #include "caf/named_actor_config.hpp"
...@@ -79,7 +80,7 @@ public: ...@@ -79,7 +80,7 @@ public:
using group_module_factory_vector = std::vector<group_module_factory>; using group_module_factory_vector = std::vector<group_module_factory>;
using config_map = std::map<std::string, config_value::dictionary>; using config_map = dictionary<config_value::dictionary>;
using string_list = std::vector<std::string>; using string_list = std::vector<std::string>;
...@@ -101,11 +102,11 @@ public: ...@@ -101,11 +102,11 @@ public:
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
/// @private /// @private
std::map<std::string, config_value::dictionary> content; dictionary<config_value::dictionary> content;
/// Sets a config by using its INI name `config_name` to `config_value`. /// Sets a config by using its INI name `config_name` to `config_value`.
template <class T> template <class T>
actor_system_config& set(const char* name, T&& value) { actor_system_config& set(string_view name, T&& value) {
return set_impl(name, config_value{std::forward<T>(value)}); return set_impl(name, config_value{std::forward<T>(value)});
} }
...@@ -403,7 +404,7 @@ private: ...@@ -403,7 +404,7 @@ private:
&make_type_erased_value<T>); &make_type_erased_value<T>);
} }
actor_system_config& set_impl(const char* name, config_value value); actor_system_config& set_impl(string_view name, config_value value);
static std::string render_sec(uint8_t, atom_value, const message&); static std::string render_sec(uint8_t, atom_value, const message&);
......
...@@ -18,9 +18,11 @@ ...@@ -18,9 +18,11 @@
#pragma once #pragma once
#include <memory>
#include <string> #include <string>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/string_view.hpp"
namespace caf { namespace caf {
...@@ -49,8 +51,8 @@ public: ...@@ -49,8 +51,8 @@ public:
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
/// Constructs a config option. /// Constructs a config option.
config_option(std::string category, const char* name, std::string description, config_option(string_view category, string_view name, string_view description,
const meta_state* meta, void* storage = nullptr); const meta_state* meta, void* value = nullptr);
config_option(config_option&&) = default; config_option(config_option&&) = default;
...@@ -58,25 +60,20 @@ public: ...@@ -58,25 +60,20 @@ public:
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
inline const std::string& category() const noexcept { /// Returns the category of the option.
return category_; string_view category() const noexcept;
}
/// Returns the /// Returns the name of the option.
inline const std::string& long_name() const noexcept { string_view long_name() const noexcept;
return long_name_;
}
inline const std::string& short_names() const noexcept { /// Returns (optional) one-letter short names of the option.
return short_names_; string_view short_names() const noexcept;
}
inline const std::string& description() const noexcept { /// Returns a human-readable description of the option.
return description_; string_view description() const noexcept;
}
/// Returns the full name for this config option as "<category>.<long name>". /// Returns the full name for this config option as "<category>.<long name>".
std::string full_name() const; string_view full_name() const noexcept;
/// Checks whether `x` holds a legal value for this option. /// Checks whether `x` holds a legal value for this option.
error check(const config_value& x) const; error check(const config_value& x) const;
...@@ -86,7 +83,7 @@ public: ...@@ -86,7 +83,7 @@ public:
void store(const config_value& x) const; void store(const config_value& x) const;
/// Returns a human-readable representation of this option's expected type. /// Returns a human-readable representation of this option's expected type.
const std::string& type_name() const noexcept; string_view type_name() const noexcept;
/// Returns whether this config option stores a boolean flag. /// Returns whether this config option stores a boolean flag.
bool is_flag() const noexcept; bool is_flag() const noexcept;
...@@ -96,10 +93,13 @@ public: ...@@ -96,10 +93,13 @@ public:
optional<config_value> get() const; optional<config_value> get() const;
private: private:
std::string category_; string_view buf_slice(size_t from, size_t to) const noexcept;
std::string long_name_;
std::string short_names_; std::unique_ptr<char[]> buf_;
std::string description_; uint16_t category_separator_;
uint16_t long_name_separator_;
uint16_t short_names_separator_;
uint16_t buf_size_;
const meta_state* meta_; const meta_state* meta_;
mutable void* value_; mutable void* value_;
}; };
......
...@@ -30,36 +30,36 @@ class config_option_adder { ...@@ -30,36 +30,36 @@ class config_option_adder {
public: public:
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
config_option_adder(config_option_set& target, const char* category); config_option_adder(config_option_set& target, string_view category);
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
/// Adds a config option to the category that synchronizes with `ref`. /// Adds a config option to the category that synchronizes with `ref`.
template <class T> template <class T>
config_option_adder& add(T& ref, const char* name, const char* description) { config_option_adder& add(T& ref, string_view name, string_view description) {
return add_impl(make_config_option(ref, category_, name, description)); return add_impl(make_config_option(ref, category_, name, description));
} }
/// Adds a config option to the category. /// Adds a config option to the category.
template <class T> template <class T>
config_option_adder& add(const char* name, const char* description) { config_option_adder& add(string_view name, string_view description) {
return add_impl(make_config_option<T>(category_, name, description)); return add_impl(make_config_option<T>(category_, name, description));
} }
/// For backward compatibility only. Do not use for new code! /// For backward compatibility only. Do not use for new code!
/// @private /// @private
config_option_adder& add_neg(bool& ref, const char* name, config_option_adder& add_neg(bool& ref, string_view name,
const char* description); string_view description);
/// For backward compatibility only. Do not use for new code! /// For backward compatibility only. Do not use for new code!
/// @private /// @private
config_option_adder& add_us(size_t& ref, const char* name, config_option_adder& add_us(size_t& ref, string_view name,
const char* description); string_view description);
/// For backward compatibility only. Do not use for new code! /// For backward compatibility only. Do not use for new code!
/// @private /// @private
config_option_adder& add_ms(size_t& ref, const char* name, config_option_adder& add_ms(size_t& ref, string_view name,
const char* description); string_view description);
private: private:
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
...@@ -72,7 +72,7 @@ private: ...@@ -72,7 +72,7 @@ private:
config_option_set& xs_; config_option_set& xs_;
/// Category for all options generated by this adder. /// Category for all options generated by this adder.
const char* category_; string_view category_;
}; };
} // namespace caf } // namespace caf
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/make_config_option.hpp" #include "caf/make_config_option.hpp"
#include "caf/pec.hpp" #include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace caf { namespace caf {
...@@ -53,10 +54,10 @@ public: ...@@ -53,10 +54,10 @@ public:
using iterator = option_vector::iterator; using iterator = option_vector::iterator;
/// Maps string keys to arbitrary (config) values. /// Maps string keys to arbitrary (config) values.
using dictionary = std::map<std::string, config_value>; using dictionary = dictionary<config_value>;
/// Categorized settings. /// Categorized settings.
using config_map = std::map<std::string, dictionary>; using config_map = caf::dictionary<dictionary>;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
...@@ -69,18 +70,18 @@ public: ...@@ -69,18 +70,18 @@ public:
/// `<prefix>#<category>.<long-name>`. Users can omit `<prefix>` /// `<prefix>#<category>.<long-name>`. Users can omit `<prefix>`
/// for options that have an empty prefix and `<category>` /// for options that have an empty prefix and `<category>`
/// if the category is "global". /// if the category is "global".
option_pointer cli_long_name_lookup(const std::string& name) const; option_pointer cli_long_name_lookup(string_view name) const;
/// Returns the first `config_option` that matches the CLI short option name. /// Returns the first `config_option` that matches the CLI short option name.
option_pointer cli_short_name_lookup(char short_name) const; option_pointer cli_short_name_lookup(char short_name) const;
/// Returns the first `config_option` that matches category and long name. /// Returns the first `config_option` that matches category and long name.
option_pointer qualified_name_lookup(const std::string& category, option_pointer qualified_name_lookup(string_view category,
const std::string& long_name) const; string_view long_name) const;
/// Returns the first `config_option` that matches the qualified name. /// Returns the first `config_option` that matches the qualified name.
/// @param name Config option name formatted as `<category>.<long-name>`. /// @param name Config option name formatted as `<category>.<long-name>`.
option_pointer qualified_name_lookup(const std::string& name) const; option_pointer qualified_name_lookup(string_view name) const;
/// Returns the number of stored config options. /// Returns the number of stored config options.
inline size_t size() const noexcept { inline size_t size() const noexcept {
...@@ -99,15 +100,15 @@ public: ...@@ -99,15 +100,15 @@ public:
/// Adds a config option to the set. /// Adds a config option to the set.
template <class T> template <class T>
config_option_set& add(const char* category, const char* name, config_option_set& add(string_view category, string_view name,
const char* description = "") { string_view description = "") {
return add(make_config_option<T>(category, name, description)); return add(make_config_option<T>(category, name, description));
} }
/// Adds a config option to the set that synchronizes its value with `ref`. /// Adds a config option to the set that synchronizes its value with `ref`.
template <class T> template <class T>
config_option_set& add(T& ref, const char* category, const char* name, config_option_set& add(T& ref, string_view category, string_view name,
const char* description = "") { string_view description = "") {
return add(make_config_option<T>(ref, category, name, description)); return add(make_config_option<T>(ref, category, name, description));
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "caf/atom.hpp" #include "caf/atom.hpp"
#include "caf/detail/bounds_checker.hpp" #include "caf/detail/bounds_checker.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/optional.hpp" #include "caf/optional.hpp"
#include "caf/string_algorithms.hpp" #include "caf/string_algorithms.hpp"
...@@ -59,7 +60,7 @@ public: ...@@ -59,7 +60,7 @@ public:
using list = std::vector<config_value>; using list = std::vector<config_value>;
using dictionary = std::map<std::string, config_value>; using dictionary = dictionary<config_value>;
using types = detail::type_list<integer, boolean, real, atom, timespan, using types = detail::type_list<integer, boolean, real, atom, timespan,
string, list, dictionary>; string, list, dictionary>;
...@@ -96,11 +97,11 @@ public: ...@@ -96,11 +97,11 @@ public:
// -- parsing ---------------------------------------------------------------- // -- parsing ----------------------------------------------------------------
/// Tries to parse a value from `str`. /// Tries to parse a value from `str`.
static expected<config_value> parse(std::string::const_iterator first, static expected<config_value> parse(string_view::iterator first,
std::string::const_iterator last); string_view::iterator last);
/// Tries to parse a value from `str`. /// Tries to parse a value from `str`.
static expected<config_value> parse(const std::string& str); static expected<config_value> parse(string_view str);
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
...@@ -175,7 +176,7 @@ private: ...@@ -175,7 +176,7 @@ private:
/// Organizes config values into categories. /// Organizes config values into categories.
/// @relates config_value /// @relates config_value
using config_value_map = std::map<std::string, config_value::dictionary>; using config_value_map = dictionary<config_value::dictionary>;
// -- SumType-like access ------------------------------------------------------ // -- SumType-like access ------------------------------------------------------
...@@ -351,12 +352,12 @@ struct config_value_access<std::vector<T>> { ...@@ -351,12 +352,12 @@ struct config_value_access<std::vector<T>> {
} }
}; };
/// Implements automagic unboxing of `std::map<std::string, V>` from a /// Implements automagic unboxing of `dictionary<V>` from a homogeneous
/// homogeneous `config_value::dictionary`. /// `config_value::dictionary`.
/// @relates config_value /// @relates config_value
template <class V> template <class V>
struct config_value_access<std::map<std::string, V>> { struct config_value_access<dictionary<V>> {
using map_type = std::map<std::string, V>; using map_type = dictionary<V>;
using kvp = std::pair<const std::string, config_value>; using kvp = std::pair<const std::string, config_value>;
...@@ -401,10 +402,9 @@ struct config_value_access<std::map<std::string, V>> { ...@@ -401,10 +402,9 @@ struct config_value_access<std::map<std::string, V>> {
/// Tries to retrieve the value associated to `name` from `xs`. /// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value /// @relates config_value
template <class T> template <class T>
optional<T> get_if(const config_value::dictionary* xs, optional<T> get_if(const config_value::dictionary* xs, string_view name) {
const std::string& name) {
// Split the name into a path. // Split the name into a path.
std::vector<std::string> path; std::vector<string_view> path;
split(path, name, "."); split(path, name, ".");
// Sanity check. // Sanity check.
if (path.size() == 0) if (path.size() == 0)
...@@ -433,7 +433,7 @@ optional<T> get_if(const config_value::dictionary* xs, ...@@ -433,7 +433,7 @@ optional<T> get_if(const config_value::dictionary* xs,
/// Retrieves the value associated to `name` from `xs`. /// Retrieves the value associated to `name` from `xs`.
/// @relates config_value /// @relates config_value
template <class T> template <class T>
T get(const config_value::dictionary& xs, const std::string& name) { T get(const config_value::dictionary& xs, string_view name) {
auto result = get_if<T>(&xs, name); auto result = get_if<T>(&xs, name);
if (result) if (result)
return std::move(*result); return std::move(*result);
...@@ -444,7 +444,7 @@ T get(const config_value::dictionary& xs, const std::string& name) { ...@@ -444,7 +444,7 @@ T get(const config_value::dictionary& xs, const std::string& name) {
/// `default_value`. /// `default_value`.
/// @relates config_value /// @relates config_value
template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>> template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>>
T get_or(const config_value::dictionary& xs, const std::string& name, T get_or(const config_value::dictionary& xs, string_view name,
const T& default_value) { const T& default_value) {
auto result = get_if<T>(&xs, name); auto result = get_if<T>(&xs, name);
if (result) if (result)
...@@ -455,13 +455,13 @@ T get_or(const config_value::dictionary& xs, const std::string& name, ...@@ -455,13 +455,13 @@ T get_or(const config_value::dictionary& xs, const std::string& name,
/// Retrieves the value associated to `name` from `xs` or returns /// Retrieves the value associated to `name` from `xs` or returns
/// `default_value`. /// `default_value`.
/// @relates config_value /// @relates config_value
std::string get_or(const config_value::dictionary& xs, const std::string& name, std::string get_or(const config_value::dictionary& xs, string_view name,
const char* default_value); const char* default_value);
/// Tries to retrieve the value associated to `name` from `xs`. /// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value /// @relates config_value
template <class T> template <class T>
optional<T> get_if(const config_value_map* xs, const std::string& name) { optional<T> get_if(const config_value_map* xs, string_view name) {
// Get the category. // Get the category.
auto pos = name.find('.'); auto pos = name.find('.');
if (pos == std::string::npos) { if (pos == std::string::npos) {
...@@ -479,7 +479,7 @@ optional<T> get_if(const config_value_map* xs, const std::string& name) { ...@@ -479,7 +479,7 @@ optional<T> get_if(const config_value_map* xs, const std::string& name) {
/// Retrieves the value associated to `name` from `xs`. /// Retrieves the value associated to `name` from `xs`.
/// @relates config_value /// @relates config_value
template <class T> template <class T>
T get(const config_value_map& xs, const std::string& name) { T get(const config_value_map& xs, string_view name) {
auto result = get_if<T>(&xs, name); auto result = get_if<T>(&xs, name);
if (result) if (result)
return std::move(*result); return std::move(*result);
...@@ -490,8 +490,7 @@ T get(const config_value_map& xs, const std::string& name) { ...@@ -490,8 +490,7 @@ T get(const config_value_map& xs, const std::string& name) {
/// `default_value`. /// `default_value`.
/// @relates config_value /// @relates config_value
template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>> template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>>
T get_or(const config_value_map& xs, const std::string& name, T get_or(const config_value_map& xs, string_view name, const T& default_value) {
const T& default_value) {
auto result = get_if<T>(&xs, name); auto result = get_if<T>(&xs, name);
if (result) if (result)
return std::move(*result); return std::move(*result);
...@@ -501,20 +500,20 @@ T get_or(const config_value_map& xs, const std::string& name, ...@@ -501,20 +500,20 @@ T get_or(const config_value_map& xs, const std::string& name,
/// Retrieves the value associated to `name` from `xs` or returns /// Retrieves the value associated to `name` from `xs` or returns
/// `default_value`. /// `default_value`.
/// @relates config_value /// @relates config_value
std::string get_or(const config_value_map& xs, const std::string& name, std::string get_or(const config_value_map& xs, string_view name,
const char* default_value); const char* default_value);
/// Tries to retrieve the value associated to `name` from `cfg`. /// Tries to retrieve the value associated to `name` from `cfg`.
/// @relates config_value /// @relates config_value
template <class T> template <class T>
optional<T> get_if(const actor_system_config* cfg, const std::string& name) { optional<T> get_if(const actor_system_config* cfg, string_view name) {
return get_if<T>(&content(*cfg), name); return get_if<T>(&content(*cfg), name);
} }
/// Retrieves the value associated to `name` from `cfg`. /// Retrieves the value associated to `name` from `cfg`.
/// @relates config_value /// @relates config_value
template <class T> template <class T>
T get(const actor_system_config& cfg, const std::string& name) { T get(const actor_system_config& cfg, string_view name) {
return get<T>(content(cfg), name); return get<T>(content(cfg), name);
} }
...@@ -522,12 +521,12 @@ T get(const actor_system_config& cfg, const std::string& name) { ...@@ -522,12 +521,12 @@ T get(const actor_system_config& cfg, const std::string& name) {
/// `default_value`. /// `default_value`.
/// @relates config_value /// @relates config_value
template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>> template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>>
T get_or(const actor_system_config& cfg, const std::string& name, T get_or(const actor_system_config& cfg, string_view name,
const T& default_value) { const T& default_value) {
return get_or(content(cfg), name, default_value); return get_or(content(cfg), name, default_value);
} }
std::string get_or(const actor_system_config& cfg, const std::string& name, std::string get_or(const actor_system_config& cfg, string_view name,
const char* default_value); const char* default_value);
/// @relates config_value /// @relates config_value
bool operator<(const config_value& x, const config_value& y); bool operator<(const config_value& x, const config_value& y);
......
...@@ -18,11 +18,11 @@ ...@@ -18,11 +18,11 @@
#pragma once #pragma once
#include <map>
#include <string> #include <string>
#include "caf/config_option_set.hpp" #include "caf/config_option_set.hpp"
#include "caf/config_value.hpp" #include "caf/config_value.hpp"
#include "caf/dictionary.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
...@@ -183,7 +183,7 @@ public: ...@@ -183,7 +183,7 @@ public:
using super = abstract_ini_consumer; using super = abstract_ini_consumer;
using config_map = std::map<std::string, config_value::dictionary>; using config_map = dictionary<config_value::dictionary>;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
......
...@@ -18,11 +18,11 @@ ...@@ -18,11 +18,11 @@
#pragma once #pragma once
#include <map>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/timestamp.hpp" #include "caf/timestamp.hpp"
...@@ -127,7 +127,7 @@ struct type_name_builder<std::vector<T>, false> { ...@@ -127,7 +127,7 @@ struct type_name_builder<std::vector<T>, false> {
}; };
template <class T> template <class T>
struct type_name_builder<std::map<std::string, T>, false> { struct type_name_builder<dictionary<T>, false> {
void operator()(std::string& result) const { void operator()(std::string& result) const {
result += "dictionary of "; result += "dictionary of ";
type_name_builder<T> g; type_name_builder<T> g;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <algorithm>
#include <iterator>
#include <map>
#include <string>
#include "caf/string_view.hpp"
namespace caf {
/// Maps strings to values of type `V`, but unlike `std::map<std::string, V>`
/// accepts `string_view` for looking up keys efficiently.
template <class V>
class dictionary {
public:
// -- member types ----------------------------------------------------------
using map_type = std::map<std::string, V>;
using key_type = typename map_type::key_type;
using mapped_type = typename map_type::mapped_type;
using value_type = typename map_type::value_type;
using allocator_type = typename map_type::allocator_type;
using size_type = typename map_type::size_type;
using difference_type = typename map_type::difference_type;
using reference = typename map_type::reference;
using const_reference = typename map_type::const_reference;
using pointer = typename map_type::pointer;
using const_pointer = typename map_type::const_pointer;
using iterator = typename map_type::iterator;
using const_iterator = typename map_type::const_iterator;
using reverse_iterator = typename map_type::reverse_iterator;
using const_reverse_iterator = typename map_type::const_reverse_iterator;
using iterator_bool_pair = std::pair<iterator, bool>;
struct mapped_type_less {
inline bool operator()(const value_type& x, string_view y) const {
return x.first < y;
}
inline bool operator()(const value_type& x, const value_type& y) const {
return x.first < y.first;
}
inline bool operator()(string_view x, const value_type& y) const {
return x < y.first;
}
};
// -- constructors, destructors, and assignment operators -------------------
dictionary() = default;
dictionary(std::initializer_list<value_type> xs) : xs_(xs) {
// nop
}
template <class InputIterator>
dictionary(InputIterator first, InputIterator last) : xs_(first, last) {
// nop
}
// -- iterator access --------------------------------------------------------
iterator begin() noexcept {
return xs_.begin();
}
const_iterator begin() const noexcept {
return xs_.begin();
}
const_iterator cbegin() const noexcept {
return begin();
}
reverse_iterator rbegin() noexcept {
return xs_.rbegin();
}
const_reverse_iterator rbegin() const noexcept {
return xs_.rbegin();
}
const_reverse_iterator crbegin() const noexcept {
return rbegin();
}
iterator end() noexcept {
return xs_.end();
}
const_iterator end() const noexcept {
return xs_.end();
}
const_iterator cend() const noexcept {
return end();
}
reverse_iterator rend() noexcept {
return xs_.rend();
}
const_reverse_iterator rend() const noexcept {
return xs_.rend();
}
const_reverse_iterator crend() const noexcept {
return rend();
}
// -- size -------------------------------------------------------------------
bool empty() const noexcept {
return xs_.empty();
}
size_type size() const noexcept {
return xs_.size();
}
// -- access to members ------------------------------------------------------
/// Gives raw access to the underlying container.
map_type& container() noexcept {
return xs_;
}
/// Gives raw access to the underlying container.
const map_type& container() const noexcept {
return xs_;
}
// -- modifiers -------------------------------------------------------------
void clear() noexcept {
return xs_.clear();
}
void swap(dictionary& other) {
xs_.swap(other.xs_);
}
// -- insertion --------------------------------------------------------------
template <class K, class T>
iterator_bool_pair emplace(K&& key, T&& value) {
auto i = lower_bound(key);
if (i == end())
return xs_.emplace(copy(std::forward<K>(key)), std::forward<T>(value));
if (i->first == key)
return {i, false};
return {xs_.emplace_hint(i, copy(std::forward<K>(key)),
std::forward<T>(value)),
true};
}
template <class T>
iterator_bool_pair insert(string_view key, T&& value) {
return emplace(key, std::forward<T>(value));
}
template <class K, class T>
iterator emplace_hint(iterator hint, K&& key, T&& value) {
if (hint == end() || hint->first > key)
return xs_.emplace(copy(std::forward<K>(key)), std::forward<T>(value))
.first;
if (hint->first == key)
return hint;
return xs_.emplace_hint(hint, copy(std::forward<K>(key)),
std::forward<T>(value));
}
template <class T>
iterator insert(iterator hint, string_view key, T&& value) {
return emplace_hint(hint, key, std::forward<T>(value));
}
template <class T>
iterator_bool_pair insert_or_assign(string_view key, T&& value) {
auto i = lower_bound(key);
if (i == end())
return xs_.emplace(copy(key), std::forward<T>(value));
if (i->first == key) {
i->second = std::forward<T>(value);
return {i, false};
}
return {xs_.emplace_hint(i, copy(key), std::forward<T>(value)), true};
}
template <class T>
iterator insert_or_assign(iterator hint, string_view key, T&& value) {
if (hint == end() || hint->first > key)
return insert_or_assign(key, std::forward<T>(value)).first;
hint = lower_bound(hint, key);
if (hint != end() && hint->first == key) {
hint->second = std::forward<T>(value);
return hint;
}
return xs_.emplace_hint(hint, copy(key), std::forward<T>(value));
}
// -- lookup -----------------------------------------------------------------
bool contains(string_view key) const noexcept {
auto i = lower_bound(key);
return !(i == end() || i->first != key);
}
size_t count(string_view key) const noexcept {
return contains(key) ? 1u : 0u;
}
iterator find(string_view key) noexcept {
auto i = lower_bound(key);
return i != end() && i->first == key ? i : end();
}
const_iterator find(string_view key) const noexcept {
auto i = lower_bound(key);
return i != end() && i->first == key ? i : end();
}
iterator lower_bound(string_view key) {
return lower_bound(begin(), key);
}
const_iterator lower_bound(string_view key) const {
return lower_bound(begin(), key);
}
iterator upper_bound(string_view key) {
mapped_type_less cmp;
return std::upper_bound(begin(), end(), key, cmp);
}
const_iterator upper_bound(string_view key) const {
mapped_type_less cmp;
return std::upper_bound(begin(), end(), key, cmp);
}
// -- element access ---------------------------------------------------------
mapped_type& operator[](string_view key) {
return insert(key, mapped_type{}).first->second;
}
private:
iterator lower_bound(iterator from, string_view key) {
mapped_type_less cmp;
return std::lower_bound(from, end(), key, cmp);
}
const_iterator lower_bound(const_iterator from, string_view key) const {
mapped_type_less cmp;
return std::lower_bound(from, end(), key, cmp);
}
// Copies the content of `str` into a new string.
static inline std::string copy(string_view str) {
return std::string{str.begin(), str.end()};
}
// Moves the content of `str` into a new string.
static inline std::string copy(std::string str) {
return str;
}
map_type xs_;
};
// @relates dictionary
template <class T>
bool operator==(const dictionary<T>& xs, const dictionary<T>& ys) {
return xs.container() == ys.container();
}
// @relates dictionary
template <class T>
bool operator!=(const dictionary<T>& xs, const dictionary<T>& ys) {
return xs.container() != ys.container();
}
// @relates dictionary
template <class T>
bool operator<(const dictionary<T>& xs, const dictionary<T>& ys) {
return xs.container() < ys.container();
}
// @relates dictionary
template <class T>
bool operator<=(const dictionary<T>& xs, const dictionary<T>& ys) {
return xs.container() <= ys.container();
}
// @relates dictionary
template <class T>
bool operator>(const dictionary<T>& xs, const dictionary<T>& ys) {
return xs.container() > ys.container();
}
// @relates dictionary
template <class T>
bool operator>=(const dictionary<T>& xs, const dictionary<T>& ys) {
return xs.container() >= ys.container();
}
} // namespace caf
...@@ -32,6 +32,7 @@ namespace caf { ...@@ -32,6 +32,7 @@ namespace caf {
// -- 1 param templates -------------------------------------------------------- // -- 1 param templates --------------------------------------------------------
template <class> class behavior_type_of; template <class> class behavior_type_of;
template <class> class dictionary;
template <class> class downstream; template <class> class downstream;
template <class> class expected; template <class> class expected;
template <class> class intrusive_ptr; template <class> class intrusive_ptr;
...@@ -119,6 +120,7 @@ class scheduled_actor; ...@@ -119,6 +120,7 @@ class scheduled_actor;
class scoped_actor; class scoped_actor;
class serializer; class serializer;
class stream_manager; class stream_manager;
class string_view;
class type_erased_tuple; class type_erased_tuple;
class type_erased_value; class type_erased_value;
class uniform_type_info_map; class uniform_type_info_map;
...@@ -142,12 +144,12 @@ struct prohibit_top_level_spawn_marker; ...@@ -142,12 +144,12 @@ struct prohibit_top_level_spawn_marker;
// -- free template functions -------------------------------------------------- // -- free template functions --------------------------------------------------
template <class T> template <class T>
config_option make_config_option(const char* category, const char* name, config_option make_config_option(string_view category, string_view name,
const char* description); string_view description);
template <class T> template <class T>
config_option make_config_option(T& storage, const char* category, config_option make_config_option(T& storage, string_view category,
const char* name, const char* description); string_view name, string_view description);
// -- enums -------------------------------------------------------------------- // -- enums --------------------------------------------------------------------
...@@ -162,8 +164,7 @@ using stream_slot = uint16_t; ...@@ -162,8 +164,7 @@ using stream_slot = uint16_t;
// -- functions ---------------------------------------------------------------- // -- functions ----------------------------------------------------------------
/// @relates actor_system_config /// @relates actor_system_config
const std::map<std::string, std::map<std::string, config_value>>& const dictionary<dictionary<config_value>>& content(const actor_system_config&);
content(const actor_system_config&);
// -- intrusive containers ----------------------------------------------------- // -- intrusive containers -----------------------------------------------------
......
...@@ -50,15 +50,15 @@ config_option::meta_state* option_meta_state_instance() { ...@@ -50,15 +50,15 @@ config_option::meta_state* option_meta_state_instance() {
/// Creates a config option that synchronizes with `storage`. /// Creates a config option that synchronizes with `storage`.
template <class T> template <class T>
config_option make_config_option(const char* category, const char* name, config_option make_config_option(string_view category, string_view name,
const char* description) { string_view description) {
return {category, name, description, detail::option_meta_state_instance<T>()}; return {category, name, description, detail::option_meta_state_instance<T>()};
} }
/// Creates a config option that synchronizes with `storage`. /// Creates a config option that synchronizes with `storage`.
template <class T> template <class T>
config_option make_config_option(T& storage, const char* category, config_option make_config_option(T& storage, string_view category,
const char* name, const char* description) { string_view name, string_view description) {
return {category, name, description, detail::option_meta_state_instance<T>(), return {category, name, description, detail::option_meta_state_instance<T>(),
std::addressof(storage)}; std::addressof(storage)};
} }
...@@ -66,21 +66,21 @@ config_option make_config_option(T& storage, const char* category, ...@@ -66,21 +66,21 @@ config_option make_config_option(T& storage, const char* category,
// -- backward compatbility, do not use for new code ! ------------------------- // -- backward compatbility, do not use for new code ! -------------------------
// Inverts the value when writing to `storage`. // Inverts the value when writing to `storage`.
config_option make_negated_config_option(bool& storage, const char* category, config_option make_negated_config_option(bool& storage, string_view category,
const char* name, string_view name,
const char* description); string_view description);
// Reads timespans, but stores an integer representing microsecond resolution. // Reads timespans, but stores an integer representing microsecond resolution.
config_option make_us_resolution_config_option(size_t& storage, config_option make_us_resolution_config_option(size_t& storage,
const char* category, string_view category,
const char* name, string_view name,
const char* description); string_view description);
// Reads timespans, but stores an integer representing millisecond resolution. // Reads timespans, but stores an integer representing millisecond resolution.
config_option make_ms_resolution_config_option(size_t& storage, config_option make_ms_resolution_config_option(size_t& storage,
const char* category, string_view category,
const char* name, string_view name,
const char* description); string_view description);
// -- specializations for common types ----------------------------------------- // -- specializations for common types -----------------------------------------
......
...@@ -39,8 +39,8 @@ inline std::string is_any_of(std::string arg) { ...@@ -39,8 +39,8 @@ inline std::string is_any_of(std::string arg) {
constexpr bool token_compress_on = false; constexpr bool token_compress_on = false;
template <class Container, class Delim> template <class Container, class Str, class Delim>
void split(Container& result, const std::string& str, const Delim& delims, void split(Container& result, const Str& str, const Delim& delims,
bool keep_all = true) { bool keep_all = true) {
size_t pos = 0; size_t pos = 0;
size_t prev = 0; size_t prev = 0;
...@@ -53,9 +53,8 @@ void split(Container& result, const std::string& str, const Delim& delims, ...@@ -53,9 +53,8 @@ void split(Container& result, const std::string& str, const Delim& delims,
} }
prev = pos + 1; prev = pos + 1;
} }
if (prev < str.size()) { if (prev < str.size())
result.push_back(str.substr(prev, std::string::npos)); result.push_back(str.substr(prev, std::string::npos));
}
} }
template <class Iterator> template <class Iterator>
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstddef>
#include <iosfwd>
#include <iterator>
#include <limits>
#include <type_traits>
#include "caf/detail/comparable.hpp"
namespace caf {
namespace detail {
// Catches `std::string`, `std::string_view` and all classes mimicing those,
// but not `std::vector<char>` or other buffers.
template <class T>
struct is_string_like {
// SFINAE checks.
template <class U>
static bool sfinae(
const U* x,
// check if `(*x)[0]` returns `const char&`
typename std::enable_if<
std::is_same<
const char&,
decltype((*x)[0])
>::value
>::type* = nullptr,
// check if `x->size()` returns an integer
typename std::enable_if<
std::is_integral<
decltype(x->size())
>::value
>::type* = nullptr,
// check if `x->compare(*x)` is well-formed and returns an integer
// (distinguishes vectors from strings)
typename std::enable_if<
std::is_integral<
decltype(x->compare(*x))
>::value
>::type* = nullptr);
// SFINAE fallback.
static void sfinae(void*);
// Result of SFINAE test.
using result_type =
decltype(sfinae(static_cast<typename std::decay<T>::type*>(nullptr)));
// Trait result.
static constexpr bool value = std::is_same<bool, result_type>::value;
};
} // namespace detail
/// Drop-in replacement for C++17 std::string_view.
class string_view : detail::comparable<string_view> {
public:
// -- member types -----------------------------------------------------------
using value_type = char;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using const_iterator = const_pointer;
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = const_reverse_iterator;
using size_type = size_t;
using difference_type = ptrdiff_t;
// -- constants --------------------------------------------------------------
static constexpr size_type npos = std::numeric_limits<size_type>::max();
// -- constructors, destructors, and assignment operators --------------------
constexpr string_view() noexcept : data_(nullptr), size_(0) {
// nop
}
constexpr string_view(const char* cstr, size_t length) noexcept
: data_(cstr),
size_(length) {
// nop
}
template <size_t N>
constexpr string_view(const char (&cstr)[N]) noexcept
: data_(cstr),
size_(N - 1) {
static_assert(N > 0, "");
}
constexpr string_view(const string_view&) noexcept = default;
template <
class T,
class = typename std::enable_if<detail::is_string_like<T>::value>::type
>
string_view(const T& str) noexcept {
auto len = str.size();
if (len == 0) {
data_ = nullptr;
size_ = 0;
} else {
data_ = &(str[0]);
size_ = str.size();
}
}
string_view& operator=(const string_view&) noexcept = default;
// -- capacity ---------------------------------------------------------------
constexpr size_type size() const noexcept {
return size_;
}
constexpr size_type length() const noexcept {
return size_;
}
constexpr size_type max_size() const noexcept {
return std::numeric_limits<size_type>::max();
}
constexpr bool empty() const noexcept {
return size_ == 0;
}
// -- iterator access --------------------------------------------------------
constexpr const_iterator begin() const noexcept {
return data_;
}
constexpr const_iterator end() const noexcept {
return data_ + size_;
}
constexpr const_iterator cbegin() const noexcept {
return begin();
}
constexpr const_iterator cend() const noexcept {
return end();
}
const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator rend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
// -- element access ---------------------------------------------------------
constexpr const_reference operator[](size_type pos) const {
return data_[pos];
}
const_reference at(size_type pos) const;
constexpr const_reference front() const {
return *data_;
}
constexpr const_reference back() const {
return data_[size_ - 1];
}
constexpr const_pointer data() const noexcept {
return data_;
}
// -- modifiers --------------------------------------------------------------
void remove_prefix(size_type n);
void remove_suffix(size_type n);
void assign(const_pointer data, size_type len);
// -- algortihms -------------------------------------------------------------
size_type copy(pointer dest, size_type n, size_type pos = 0) const;
string_view substr(size_type pos = 0, size_type n = npos) const noexcept;
int compare(string_view s) const noexcept;
int compare(size_type pos1, size_type n1, string_view str) const noexcept;
int compare(size_type pos1, size_type n1, string_view str,
size_type pos2, size_type n2) const noexcept;
int compare(const_pointer str) const noexcept;
int compare(size_type pos, size_type n, const_pointer str) const noexcept;
int compare(size_type pos1, size_type n1,
const_pointer s, size_type n2) const noexcept;
size_type find(string_view str, size_type pos = 0) const noexcept;
size_type find(value_type ch, size_type pos = 0) const noexcept;
size_type find(const_pointer str, size_type pos, size_type n) const noexcept;
size_type find(const_pointer str, size_type pos = 0) const noexcept;
size_type rfind(string_view str, size_type pos = npos) const noexcept;
size_type rfind(value_type ch, size_type pos = npos) const noexcept;
size_type rfind(const_pointer str, size_type pos, size_type n) const noexcept;
size_type rfind(const_pointer str, size_type pos = npos) const noexcept;
size_type find_first_of(string_view str, size_type pos = 0) const noexcept;
size_type find_first_of(value_type ch, size_type pos = 0) const noexcept;
size_type find_first_of(const_pointer str, size_type pos,
size_type n) const noexcept;
size_type find_first_of(const_pointer str, size_type pos = 0) const noexcept;
size_type find_last_of(string_view str, size_type pos = npos) const noexcept;
size_type find_last_of(value_type ch, size_type pos = npos) const noexcept;
size_type find_last_of(const_pointer str, size_type pos,
size_type n) const noexcept;
size_type find_last_of(const_pointer str,
size_type pos = npos) const noexcept;
size_type find_first_not_of(string_view str,
size_type pos = 0) const noexcept;
size_type find_first_not_of(value_type ch, size_type pos = 0) const noexcept;
size_type find_first_not_of(const_pointer str, size_type pos,
size_type n) const noexcept;
size_type find_first_not_of(const_pointer str,
size_type pos = 0) const noexcept;
size_type find_last_not_of(string_view str,
size_type pos = npos) const noexcept;
size_type find_last_not_of(value_type ch,
size_type pos = npos) const noexcept;
size_type find_last_not_of(const_pointer str, size_type pos,
size_type n) const noexcept;
size_type find_last_not_of(const_pointer str,
size_type pos = npos) const noexcept;
private:
const char* data_;
size_t size_;
};
} // namespace caf
namespace std {
std::ostream& operator<<(std::ostream& out, caf::string_view);
} // namespace std
...@@ -388,7 +388,7 @@ actor_system_config::add_error_category(atom_value x, error_renderer y) { ...@@ -388,7 +388,7 @@ actor_system_config::add_error_category(atom_value x, error_renderer y) {
return *this; return *this;
} }
actor_system_config& actor_system_config::set_impl(const char* name, actor_system_config& actor_system_config::set_impl(string_view name,
config_value value) { config_value value) {
auto opt = custom_options_.qualified_name_lookup(name); auto opt = custom_options_.qualified_name_lookup(name);
if (opt != nullptr && opt->check(value) == none) { if (opt != nullptr && opt->check(value) == none) {
...@@ -454,7 +454,7 @@ void actor_system_config::extract_config_file_path(string_list& args) { ...@@ -454,7 +454,7 @@ void actor_system_config::extract_config_file_path(string_list& args) {
args.erase(i); args.erase(i);
} }
const std::map<std::string, std::map<std::string, config_value>>& const dictionary<dictionary<config_value>>&
content(const actor_system_config& cfg) { content(const actor_system_config& cfg) {
return cfg.content; return cfg.content;
} }
......
...@@ -18,8 +18,9 @@ ...@@ -18,8 +18,9 @@
#include "caf/config_option.hpp" #include "caf/config_option.hpp"
#include <cstring> #include <algorithm>
#include <iostream> #include <limits>
#include <numeric>
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/config_value.hpp" #include "caf/config_value.hpp"
...@@ -29,41 +30,73 @@ ...@@ -29,41 +30,73 @@
using std::move; using std::move;
using std::string; using std::string;
namespace { namespace caf {
// -- constructors, destructors, and assignment operators ----------------------
string get_long_name(const char* name) { config_option::config_option(string_view category, string_view name,
auto i= strchr(name, ','); string_view description, const meta_state* meta,
return i != nullptr ? string{name, i} : string{name}; void* value)
: meta_(meta),
value_(value) {
using std::copy;
using std::accumulate;
auto comma = name.find(',');
auto long_name = name.substr(0, comma);
auto short_names = comma == string_view::npos ? string_view{}
: name.substr(comma + 1);
auto total_size = [](std::initializer_list<string_view> xs) {
return (xs.size() - 1) // one separator between all fields
+ accumulate(xs.begin(), xs.end(), size_t{0},
[](size_t x, string_view sv) { return x + sv.size(); });
};
auto ts = total_size({category, long_name, short_names, description});
CAF_ASSERT(ts <= std::numeric_limits<uint16_t>::max());
buf_size_ = static_cast<uint16_t>(ts);
buf_.reset(new char[ts]);
// fille the buffer with "<category>.<long-name>,<short-name>,<descriptions>"
auto first = buf_.get();
auto i = first;
auto pos = [&] {
return static_cast<uint16_t>(std::distance(first, i));
};
// <category>.
i = copy(category.begin(), category.end(), i);
category_separator_ = pos();
*i++ = '.';
// <long-name>,
i = copy(long_name.begin(), long_name.end(), i);
long_name_separator_ = pos();
*i++ = ',';
// <short-names>,
i = copy(short_names.begin(), short_names.end(), i);
short_names_separator_ = pos();
*i++ = ',';
// <description>
copy(description.begin(), description.end(), i);
CAF_ASSERT(pos() == buf_size_);
} }
string get_short_names(const char* name) { // -- properties ---------------------------------------------------------------
auto substr = strchr(name, ',');
if (substr != nullptr) string_view config_option::category() const noexcept {
return ++substr; return buf_slice(0, category_separator_);
return string{};
} }
} // namespace <anonymous> string_view config_option::long_name() const noexcept {
return buf_slice(category_separator_ + 1, long_name_separator_);
}
namespace caf { string_view config_option::short_names() const noexcept {
return buf_slice(long_name_separator_ + 1, short_names_separator_);
}
config_option::config_option(string category, const char* name, string_view config_option::description() const noexcept {
string description, const meta_state* meta, return buf_slice(short_names_separator_ + 1, buf_size_);
void* value)
: category_(move(category)),
long_name_(get_long_name(name)),
short_names_(get_short_names(name)),
description_(move(description)),
meta_(meta),
value_(value) {
CAF_ASSERT(meta_ != nullptr);
} }
string config_option::full_name() const { string_view config_option::full_name() const noexcept {
std::string result = category(); return buf_slice(0, long_name_separator_);
result += '.';
result += long_name_;
return result;
} }
error config_option::check(const config_value& x) const { error config_option::check(const config_value& x) const {
...@@ -78,7 +111,7 @@ void config_option::store(const config_value& x) const { ...@@ -78,7 +111,7 @@ void config_option::store(const config_value& x) const {
} }
} }
const std::string& config_option::type_name() const noexcept { string_view config_option::type_name() const noexcept {
return meta_->type_name; return meta_->type_name;
} }
...@@ -92,4 +125,9 @@ optional<config_value> config_option::get() const { ...@@ -92,4 +125,9 @@ optional<config_value> config_option::get() const {
return none; return none;
} }
string_view config_option::buf_slice(size_t from, size_t to) const noexcept {
CAF_ASSERT(from <= to);
return {buf_.get() + from, to - from};
}
} // namespace caf } // namespace caf
...@@ -23,26 +23,26 @@ ...@@ -23,26 +23,26 @@
namespace caf { namespace caf {
config_option_adder::config_option_adder(config_option_set& target, config_option_adder::config_option_adder(config_option_set& target,
const char* category) string_view category)
: xs_(target), : xs_(target),
category_(category) { category_(category) {
// nop // nop
} }
config_option_adder& config_option_adder::add_neg(bool& ref, const char* name, config_option_adder& config_option_adder::add_neg(bool& ref, string_view name,
const char* description) { string_view description) {
return add_impl(make_negated_config_option(ref, category_, return add_impl(make_negated_config_option(ref, category_,
name, description)); name, description));
} }
config_option_adder& config_option_adder::add_us(size_t& ref, const char* name, config_option_adder& config_option_adder::add_us(size_t& ref, string_view name,
const char* description) { string_view description) {
return add_impl(make_us_resolution_config_option(ref, category_, return add_impl(make_us_resolution_config_option(ref, category_,
name, description)); name, description));
} }
config_option_adder& config_option_adder::add_ms(size_t& ref, const char* name, config_option_adder& config_option_adder::add_ms(size_t& ref, string_view name,
const char* description) { string_view description) {
return add_impl(make_ms_resolution_config_option(ref, category_, return add_impl(make_ms_resolution_config_option(ref, category_,
name, description)); name, description));
} }
......
...@@ -34,19 +34,13 @@ struct string_builder { ...@@ -34,19 +34,13 @@ struct string_builder {
std::string result; std::string result;
}; };
template <size_t N> string_builder& operator<<(string_builder& builder, char ch) {
string_builder& operator<<(string_builder& builder, const char (&cstr)[N]) { builder.result += ch;
builder.result.append(cstr, N - 1);
return builder; return builder;
} }
string_builder& operator<<(string_builder& builder, char c) { string_builder& operator<<(string_builder& builder, caf::string_view str) {
builder.result += c; builder.result.append(str.data(), str.size());
return builder;
}
string_builder& operator<<(string_builder& builder, const std::string& str) {
builder.result += str;
return builder; return builder;
} }
...@@ -94,8 +88,8 @@ std::string config_option_set::help_text(bool global_only) const { ...@@ -94,8 +88,8 @@ std::string config_option_set::help_text(bool global_only) const {
}; };
// Sort argument + description by category. // Sort argument + description by category.
using pair = std::pair<std::string, option_pointer>; using pair = std::pair<std::string, option_pointer>;
std::set<std::string> categories; std::set<string_view> categories;
std::multimap<std::string, pair> args; std::multimap<string_view, pair> args;
size_t max_arg_size = 0; size_t max_arg_size = 0;
for (auto& opt : opts_) { for (auto& opt : opts_) {
if (!global_only || opt.category() == "global") { if (!global_only || opt.category() == "global") {
...@@ -132,7 +126,7 @@ auto config_option_set::parse(config_map& config, argument_iterator first, ...@@ -132,7 +126,7 @@ auto config_option_set::parse(config_map& config, argument_iterator first,
auto consume = [&](const config_option& opt, iter arg_begin, iter arg_end) { auto consume = [&](const config_option& opt, iter arg_begin, iter arg_end) {
// Extract option name and category. // Extract option name and category.
auto opt_name = opt.long_name(); auto opt_name = opt.long_name();
string opt_ctg = opt.category(); auto opt_ctg = opt.category();
// Try inserting a new submap into the config or fill existing one. // Try inserting a new submap into the config or fill existing one.
auto& submap = config[opt_ctg]; auto& submap = config[opt_ctg];
// Flags only consume the current element. // Flags only consume the current element.
...@@ -145,7 +139,9 @@ auto config_option_set::parse(config_map& config, argument_iterator first, ...@@ -145,7 +139,9 @@ auto config_option_set::parse(config_map& config, argument_iterator first,
} else { } else {
if (arg_begin == arg_end) if (arg_begin == arg_end)
return pec::missing_argument; return pec::missing_argument;
auto val = config_value::parse(arg_begin, arg_end); auto slice_size = static_cast<size_t>(std::distance(arg_begin, arg_end));
string_view slice{&*arg_begin, slice_size};
auto val = config_value::parse(slice);
if (!val) if (!val)
return pec::illegal_argument; return pec::illegal_argument;
if (opt.check(*val) != none) if (opt.check(*val) != none)
...@@ -224,12 +220,12 @@ config_option_set::parse(config_map& config, ...@@ -224,12 +220,12 @@ config_option_set::parse(config_map& config,
} }
config_option_set::option_pointer config_option_set::option_pointer
config_option_set::cli_long_name_lookup(const string& name) const { config_option_set::cli_long_name_lookup(string_view name) const {
// We accept "caf#" prefixes for backward compatibility, but ignore them. // We accept "caf#" prefixes for backward compatibility, but ignore them.
size_t offset = name.compare(0, 4, "caf#") != 0 ? 0u : 4u; size_t offset = name.compare(0, 4, "caf#") != 0 ? 0u : 4u;
// Extract category and long name. // Extract category and long name.
string category; string_view category;
string long_name; string_view long_name;
auto sep = name.find('.', offset); auto sep = name.find('.', offset);
if (sep == string::npos) { if (sep == string::npos) {
category = "global"; category = "global";
...@@ -255,15 +251,15 @@ config_option_set::cli_short_name_lookup(char short_name) const { ...@@ -255,15 +251,15 @@ config_option_set::cli_short_name_lookup(char short_name) const {
} }
config_option_set::option_pointer config_option_set::option_pointer
config_option_set::qualified_name_lookup(const std::string& category, config_option_set::qualified_name_lookup(string_view category,
const std::string& long_name) const { string_view long_name) const {
return detail::ptr_find_if(opts_, [&](const config_option& opt) { return detail::ptr_find_if(opts_, [&](const config_option& opt) {
return opt.category() == category && opt.long_name() == long_name; return opt.category() == category && opt.long_name() == long_name;
}); });
} }
config_option_set::option_pointer config_option_set::option_pointer
config_option_set::qualified_name_lookup(const std::string& name) const { config_option_set::qualified_name_lookup(string_view name) const {
auto sep = name.find('.'); auto sep = name.find('.');
if (sep == string::npos) if (sep == string::npos)
return nullptr; return nullptr;
......
...@@ -50,8 +50,8 @@ config_value::~config_value() { ...@@ -50,8 +50,8 @@ config_value::~config_value() {
// -- parsing ------------------------------------------------------------------ // -- parsing ------------------------------------------------------------------
expected<config_value> config_value::parse(std::string::const_iterator first, expected<config_value> config_value::parse(string_view::iterator first,
std::string::const_iterator last) { string_view::iterator last) {
using namespace detail; using namespace detail;
auto i = first; auto i = first;
// Sanity check. // Sanity check.
...@@ -62,7 +62,7 @@ expected<config_value> config_value::parse(std::string::const_iterator first, ...@@ -62,7 +62,7 @@ expected<config_value> config_value::parse(std::string::const_iterator first,
if (++i == last) if (++i == last)
return make_error(pec::unexpected_eof); return make_error(pec::unexpected_eof);
// Dispatch to parser. // Dispatch to parser.
parser::state<std::string::const_iterator> res; parser::state<string_view::iterator> res;
detail::ini_value_consumer f; detail::ini_value_consumer f;
res.i = i; res.i = i;
res.e = last; res.e = last;
...@@ -84,7 +84,7 @@ expected<config_value> config_value::parse(std::string::const_iterator first, ...@@ -84,7 +84,7 @@ expected<config_value> config_value::parse(std::string::const_iterator first,
} }
} }
expected<config_value> config_value::parse(const std::string& str) { expected<config_value> config_value::parse(string_view str) {
return parse(str.begin(), str.end()); return parse(str.begin(), str.end());
} }
...@@ -132,15 +132,15 @@ std::string get_or(const config_value::dictionary& xs, const std::string& name, ...@@ -132,15 +132,15 @@ std::string get_or(const config_value::dictionary& xs, const std::string& name,
return default_value; return default_value;
} }
std::string get_or(const std::map<std::string, config_value::dictionary>& xs, std::string get_or(const dictionary<config_value::dictionary>& xs,
const std::string& name, const char* default_value) { string_view name, const char* default_value) {
auto result = get_if<std::string>(&xs, name); auto result = get_if<std::string>(&xs, name);
if (result) if (result)
return std::move(*result); return std::move(*result);
return default_value; return default_value;
} }
std::string get_or(const actor_system_config& cfg, const std::string& name, std::string get_or(const actor_system_config& cfg, string_view name,
const char* default_value) { const char* default_value) {
return get_or(content(cfg), name, default_value); return get_or(content(cfg), name, default_value);
} }
......
...@@ -129,23 +129,23 @@ config_option::meta_state bool_meta_state{ ...@@ -129,23 +129,23 @@ config_option::meta_state bool_meta_state{
} // namespace detail } // namespace detail
config_option make_negated_config_option(bool& storage, const char* category, config_option make_negated_config_option(bool& storage, string_view category,
const char* name, string_view name,
const char* description) { string_view description) {
return {category, name, description, &bool_neg_meta, &storage}; return {category, name, description, &bool_neg_meta, &storage};
} }
config_option make_us_resolution_config_option(size_t& storage, config_option make_us_resolution_config_option(size_t& storage,
const char* category, string_view category,
const char* name, string_view name,
const char* description) { string_view description) {
return {category, name, description, &us_res_meta, &storage}; return {category, name, description, &us_res_meta, &storage};
} }
config_option make_ms_resolution_config_option(size_t& storage, config_option make_ms_resolution_config_option(size_t& storage,
const char* category, string_view category,
const char* name, string_view name,
const char* description) { string_view description) {
return {category, name, description, &ms_res_meta, &storage}; return {category, name, description, &ms_res_meta, &storage};
} }
......
This diff is collapsed.
...@@ -30,9 +30,9 @@ using std::string; ...@@ -30,9 +30,9 @@ using std::string;
namespace { namespace {
constexpr const char* category = "category"; constexpr string_view category = "category";
constexpr const char* name = "name"; constexpr string_view name = "name";
constexpr const char* explanation = "explanation"; constexpr string_view explanation = "explanation";
template<class T> template<class T>
constexpr int64_t overflow() { constexpr int64_t overflow() {
...@@ -45,7 +45,7 @@ constexpr int64_t underflow() { ...@@ -45,7 +45,7 @@ constexpr int64_t underflow() {
} }
template <class T> template <class T>
optional<T> read(const std::string& arg) { optional<T> read(string_view arg) {
auto co = make_config_option<T>(category, name, explanation); auto co = make_config_option<T>(category, name, explanation);
auto res = config_value::parse(arg); auto res = config_value::parse(arg);
if (res && holds_alternative<T>(*res)) { if (res && holds_alternative<T>(*res)) {
......
...@@ -62,7 +62,7 @@ CAF_TEST(lookup) { ...@@ -62,7 +62,7 @@ CAF_TEST(lookup) {
CAF_TEST(parse with ref syncing) { CAF_TEST(parse with ref syncing) {
using ls = vector<string>; // list of strings using ls = vector<string>; // list of strings
using ds = std::map<string, string>; // dictionary of strings using ds = dictionary<string>; // dictionary of strings
auto foo_i = 0; auto foo_i = 0;
auto foo_f = 0.f; auto foo_f = 0.f;
auto foo_b = false; auto foo_b = false;
...@@ -74,8 +74,8 @@ CAF_TEST(parse with ref syncing) { ...@@ -74,8 +74,8 @@ CAF_TEST(parse with ref syncing) {
.add<bool>(foo_b, "foo", "b,b", "") .add<bool>(foo_b, "foo", "b,b", "")
.add<string>(bar_s, "bar", "s,s", "") .add<string>(bar_s, "bar", "s,s", "")
.add<vector<string>>(bar_l, "bar", "l,l", "") .add<vector<string>>(bar_l, "bar", "l,l", "")
.add<std::map<string, string>>(bar_d, "bar", "d,d", ""); .add<dictionary<string>>(bar_d, "bar", "d,d", "");
std::map<std::string, config_value::dictionary> cfg; dictionary<config_value::dictionary> cfg;
vector<string> args{"-i42", vector<string> args{"-i42",
"-f", "-f",
"1e12", "1e12",
...@@ -103,7 +103,7 @@ CAF_TEST(parse with ref syncing) { ...@@ -103,7 +103,7 @@ CAF_TEST(parse with ref syncing) {
CAF_TEST(implicit global) { CAF_TEST(implicit global) {
opts.add<int>("global", "value").add<bool>("global", "help"); opts.add<int>("global", "value").add<bool>("global", "help");
CAF_MESSAGE("test long option with argument"); CAF_MESSAGE("test long option with argument");
std::map<std::string, config_value::dictionary> cfg; dictionary<config_value::dictionary> cfg;
auto res = opts.parse(cfg, {"--value=42"}); auto res = opts.parse(cfg, {"--value=42"});
CAF_CHECK_EQUAL(res.first, pec::success); CAF_CHECK_EQUAL(res.first, pec::success);
CAF_CHECK_EQUAL(get_if<int>(&cfg, "global.value"), 42); CAF_CHECK_EQUAL(get_if<int>(&cfg, "global.value"), 42);
......
...@@ -31,8 +31,10 @@ ...@@ -31,8 +31,10 @@
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/pec.hpp" #include "caf/pec.hpp"
#include "caf/variant.hpp" #include "caf/variant.hpp"
#include "caf/string_view.hpp"
using std::string;
using namespace std;
using namespace caf; using namespace caf;
namespace { namespace {
...@@ -44,7 +46,7 @@ using dictionary = config_value::dictionary; ...@@ -44,7 +46,7 @@ using dictionary = config_value::dictionary;
struct dictionary_builder { struct dictionary_builder {
dictionary dict; dictionary dict;
dictionary_builder&& add(const char* key, config_value value) && { dictionary_builder&& add(string_view key, config_value value) && {
dict.emplace(key, std::move(value)); dict.emplace(key, std::move(value));
return std::move(*this); return std::move(*this);
} }
...@@ -69,8 +71,8 @@ config_value cfg_lst(Ts&&... xs) { ...@@ -69,8 +71,8 @@ config_value cfg_lst(Ts&&... xs) {
} }
// TODO: switch to std::operator""s when switching to C++14 // TODO: switch to std::operator""s when switching to C++14
std::string operator"" _s(const char* str, size_t size) { string operator"" _s(const char* str, size_t size) {
return std::string(str, size); return string(str, size);
} }
} // namespace <anonymous> } // namespace <anonymous>
...@@ -158,7 +160,7 @@ CAF_TEST(append) { ...@@ -158,7 +160,7 @@ CAF_TEST(append) {
} }
CAF_TEST(homogeneous dictionary) { CAF_TEST(homogeneous dictionary) {
using integer_map = std::map<std::string, int64_t>; using integer_map = caf::dictionary<int64_t>;
auto xs = dict() auto xs = dict()
.add("value-1", config_value{100000}) .add("value-1", config_value{100000})
.add("value-2", config_value{2}) .add("value-2", config_value{2})
...@@ -182,7 +184,7 @@ CAF_TEST(homogeneous dictionary) { ...@@ -182,7 +184,7 @@ CAF_TEST(homogeneous dictionary) {
} }
CAF_TEST(heterogeneous dictionary) { CAF_TEST(heterogeneous dictionary) {
using string_list = std::vector<std::string>; using string_list = std::vector<string>;
auto xs = dict() auto xs = dict()
.add("scheduler", dict() .add("scheduler", dict()
.add("policy", config_value{atom("none")}) .add("policy", config_value{atom("none")})
...@@ -206,7 +208,7 @@ CAF_TEST(successful parsing) { ...@@ -206,7 +208,7 @@ CAF_TEST(successful parsing) {
// references when comparing values. Since we call get<T>() on the result of // references when comparing values. Since we call get<T>() on the result of
// parse(), we would end up with a reference to a temporary. // parse(), we would end up with a reference to a temporary.
config_value parsed; config_value parsed;
auto parse = [&](const std::string& str) -> config_value& { auto parse = [&](const string& str) -> config_value& {
auto x = config_value::parse(str); auto x = config_value::parse(str);
if (!x) if (!x)
CAF_FAIL("cannot parse " << str << ": assumed a result but error " CAF_FAIL("cannot parse " << str << ": assumed a result but error "
...@@ -214,7 +216,7 @@ CAF_TEST(successful parsing) { ...@@ -214,7 +216,7 @@ CAF_TEST(successful parsing) {
parsed = std::move(*x); parsed = std::move(*x);
return parsed; return parsed;
}; };
using di = std::map<string, int>; // Dictionary-of-integers. using di = caf::dictionary<int>; // Dictionary-of-integers.
using ls = std::vector<string>; // List-of-strings. using ls = std::vector<string>; // List-of-strings.
using li = std::vector<int>; // List-of-integers. using li = std::vector<int>; // List-of-integers.
using lli = std::vector<li>; // List-of-list-of-integers. using lli = std::vector<li>; // List-of-list-of-integers.
...@@ -235,7 +237,7 @@ CAF_TEST(successful parsing) { ...@@ -235,7 +237,7 @@ CAF_TEST(successful parsing) {
} }
CAF_TEST(unsuccessful parsing) { CAF_TEST(unsuccessful parsing) {
auto parse = [](const std::string& str) { auto parse = [](const string& str) {
auto x = config_value::parse(str); auto x = config_value::parse(str);
if (x) if (x)
CAF_FAIL("assumed an error but got a result"); CAF_FAIL("assumed an error but got a result");
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE dictionary
#include "caf/test/dsl.hpp"
#include "caf/dictionary.hpp"
using namespace caf;
namespace {
using int_dict = dictionary<int>;
struct fixture {
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(dictionary_tests, fixture)
CAF_TEST(construction and comparions) {
int_dict xs;
CAF_CHECK_EQUAL(xs.empty(), true);
CAF_CHECK_EQUAL(xs.size(), 0u);
int_dict ys{{"foo", 1}, {"bar", 2}};
CAF_CHECK_EQUAL(ys.empty(), false);
CAF_CHECK_EQUAL(ys.size(), 2u);
CAF_CHECK_NOT_EQUAL(xs, ys);
int_dict zs{ys.begin(), ys.end()};
CAF_CHECK_EQUAL(zs.empty(), false);
CAF_CHECK_EQUAL(zs.size(), 2u);
CAF_CHECK_EQUAL(ys, zs);
zs.clear();
CAF_CHECK_EQUAL(zs.empty(), true);
CAF_CHECK_EQUAL(zs.size(), 0u);
CAF_CHECK_EQUAL(xs, zs);
}
CAF_TEST(iterators) {
using std::equal;
using vector_type = std::vector<int_dict::value_type>;
int_dict xs{{"a", 1}, {"b", 2}, {"c", 3}};
vector_type ys{{"a", 1}, {"b", 2}, {"c", 3}};
CAF_CHECK(equal(xs.begin(), xs.end(), ys.begin()));
CAF_CHECK(equal(xs.cbegin(), xs.cend(), ys.cbegin()));
CAF_CHECK(equal(xs.rbegin(), xs.rend(), ys.rbegin()));
CAF_CHECK(equal(xs.crbegin(), xs.crend(), ys.crbegin()));
}
CAF_TEST(swapping) {
int_dict xs{{"foo", 1}, {"bar", 2}};
int_dict ys;
int_dict zs{{"foo", 1}, {"bar", 2}};
CAF_CHECK_NOT_EQUAL(xs, ys);
CAF_CHECK_NOT_EQUAL(ys, zs);
CAF_CHECK_EQUAL(xs, zs);
xs.swap(ys);
CAF_CHECK_NOT_EQUAL(xs, ys);
CAF_CHECK_EQUAL(ys, zs);
CAF_CHECK_NOT_EQUAL(xs, zs);
}
CAF_TEST(insertion) {
int_dict xs;
CAF_CHECK_EQUAL(xs.insert("a", 1).second, true);
CAF_CHECK_EQUAL(xs.insert("b", 2).second, true);
CAF_CHECK_EQUAL(xs.insert("c", 3).second, true);
CAF_CHECK_EQUAL(xs.insert("c", 4).second, false);
int_dict ys;
CAF_CHECK_EQUAL(ys.insert_or_assign("a", 1).second, true);
CAF_CHECK_EQUAL(ys.insert_or_assign("b", 2).second, true);
CAF_CHECK_EQUAL(ys.insert_or_assign("c", 0).second, true);
CAF_CHECK_EQUAL(ys.insert_or_assign("c", 3).second, false);
CAF_CHECK_EQUAL(xs, ys);
}
CAF_TEST(insertion with hint) {
int_dict xs;
auto xs_last = xs.end();
auto xs_insert = [&](string_view key, int val) {
xs_last = xs.insert(xs_last, key, val);
};
xs_insert("a", 1);
xs_insert("c", 3);
xs_insert("b", 2);
xs_insert("c", 4);
int_dict ys;
auto ys_last = ys.end();
auto ys_insert_or_assign = [&](string_view key, int val) {
ys_last = ys.insert_or_assign(ys_last, key, val);
};
ys_insert_or_assign("a", 1);
ys_insert_or_assign("c", 0);
ys_insert_or_assign("b", 2);
ys_insert_or_assign("c", 3);
CAF_CHECK_EQUAL(xs, ys);
}
CAF_TEST(bounds) {
int_dict xs{{"a", 1}, {"b", 2}, {"c", 3}, {"d", 4}};
const int_dict& const_xs = xs;
CAF_CHECK_EQUAL(xs.lower_bound("c")->first, "c");
CAF_CHECK_EQUAL(xs.upper_bound("c")->first, "d");
CAF_CHECK_EQUAL(const_xs.lower_bound("c")->first, "c");
CAF_CHECK_EQUAL(const_xs.upper_bound("c")->first, "d");
}
CAF_TEST(find) {
int_dict xs{{"a", 1}, {"b", 2}, {"c", 3}, {"d", 4}};
const int_dict& const_xs = xs;
CAF_CHECK_EQUAL(xs.find("e"), xs.end());
CAF_CHECK_EQUAL(xs.find("a")->second, 1);
CAF_CHECK_EQUAL(xs.find("c")->second, 3);
CAF_CHECK_EQUAL(const_xs.find("e"), xs.end());
CAF_CHECK_EQUAL(const_xs.find("a")->second, 1);
CAF_CHECK_EQUAL(const_xs.find("c")->second, 3);
}
CAF_TEST(element access) {
int_dict xs{{"a", 1}, {"b", 2}, {"c", 3}, {"d", 4}};
CAF_CHECK_EQUAL(xs["a"], 1);
CAF_CHECK_EQUAL(xs["b"], 2);
CAF_CHECK_EQUAL(xs["e"], 0);
}
CAF_TEST_FIXTURE_SCOPE_END()
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE string_view
#include "caf/test/dsl.hpp"
#include "caf/string_view.hpp"
using namespace caf;
namespace {
struct fixture {
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(string_view_tests, fixture)
CAF_TEST(default construction) {
string_view x;
string_view y;
CAF_CHECK(x.empty());
CAF_CHECK_EQUAL(x.size(), 0u);
CAF_CHECK_EQUAL(x.data(), nullptr);
CAF_CHECK_EQUAL(y, y);
}
CAF_TEST(cstring conversion) {
string_view x = "abc";
CAF_CHECK_EQUAL(x.size(), 3u);
CAF_CHECK_EQUAL(x[0], 'a');
CAF_CHECK_EQUAL(x[1], 'b');
CAF_CHECK_EQUAL(x[2], 'c');
CAF_CHECK_EQUAL(x, "abc");
x = "def";
CAF_CHECK_NOT_EQUAL(x, "abc");
CAF_CHECK_EQUAL(x, "def");
}
CAF_TEST(string conversion) {
std::string x = "abc";
string_view y;
y = x;
CAF_CHECK_EQUAL(x, y);
auto f = [&](string_view z) {
CAF_CHECK_EQUAL(x, z);
};
f(x);
}
CAF_TEST(substrings) {
string_view x = "abcdefghi";
CAF_CHECK(x.remove_prefix(3), "defghi");
CAF_CHECK(x.remove_suffix(3), "abcdef");
CAF_CHECK(x.substr(3, 3), "def");
CAF_CHECK(x.remove_prefix(9), "");
CAF_CHECK(x.remove_suffix(9), "");
CAF_CHECK(x.substr(9), "");
CAF_CHECK(x.substr(0, 0), "");
}
CAF_TEST(compare) {
// testees
string_view x = "abc";
string_view y = "bcd";
string_view z = "cde";
// x.compare full strings
CAF_CHECK(x.compare("abc") == 0);
CAF_CHECK(x.compare(y) < 0);
CAF_CHECK(x.compare(z) < 0);
// y.compare full strings
CAF_CHECK(y.compare(x) > 0);
CAF_CHECK(y.compare("bcd") == 0);
CAF_CHECK(y.compare(z) < 0);
// z.compare full strings
CAF_CHECK(z.compare(x) > 0);
CAF_CHECK(z.compare(y) > 0);
CAF_CHECK(z.compare("cde") == 0);
// x.compare substrings
CAF_CHECK(x.compare(0, 3, "abc") == 0);
CAF_CHECK(x.compare(1, 2, y, 0, 2) == 0);
CAF_CHECK(x.compare(2, 1, z, 0, 1) == 0);
CAF_CHECK(x.compare(2, 1, z, 0, 2) == 0);
}
CAF_TEST(copy) {
char buf[10];
string_view str = "hello";
auto n = str.copy(buf, str.size());
CAF_CHECK_EQUAL(n, 5u);
buf[n] = '\0';
CAF_CHECK_EQUAL(str, string_view(buf, n));
CAF_CHECK(strcmp("hello", buf) == 0);
n = str.copy(buf, 10, 3);
buf[n] = '\0';
CAF_CHECK_EQUAL(string_view(buf, n), "lo");
CAF_CHECK(strcmp("lo", buf) == 0);
}
CAF_TEST(find) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find('a'), y.find('a'));
CAF_CHECK_EQUAL(x.find('b'), y.find('b'));
CAF_CHECK_EQUAL(x.find('g'), y.find('g'));
CAF_CHECK_EQUAL(x.find('a', 1), y.find('a', 1));
CAF_CHECK_EQUAL(x.find("a"), y.find("a"));
CAF_CHECK_EQUAL(x.find("bc"), y.find("bc"));
CAF_CHECK_EQUAL(x.find("ce"), y.find("ce"));
CAF_CHECK_EQUAL(x.find("bc", 1), y.find("bc", 1));
CAF_CHECK_EQUAL(x.find("bc", 1, 0), y.find("bc", 1, 0));
CAF_CHECK_EQUAL(x.find("bc", 0, 1), y.find("bc", 0, 1));
CAF_CHECK_EQUAL(x.find("bc", 2, 10), y.find("bc", 2, 10));
}
CAF_TEST(rfind) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abccba";
std::string y = "abccba";
CAF_CHECK_EQUAL(x.rfind('a'), y.rfind('a'));
CAF_CHECK_EQUAL(x.rfind('b'), y.rfind('b'));
CAF_CHECK_EQUAL(x.rfind('g'), y.rfind('g'));
CAF_CHECK_EQUAL(x.rfind('a', 1), y.rfind('a', 1));
CAF_CHECK_EQUAL(x.rfind("a"), y.rfind("a"));
CAF_CHECK_EQUAL(x.rfind("bc"), y.rfind("bc"));
CAF_CHECK_EQUAL(x.rfind("ce"), y.rfind("ce"));
CAF_CHECK_EQUAL(x.rfind("bc", 1), y.rfind("bc", 1));
CAF_CHECK_EQUAL(x.rfind("bc", 1, 0), y.rfind("bc", 1, 0));
CAF_CHECK_EQUAL(x.rfind("bc", 0, 1), y.rfind("bc", 0, 1));
CAF_CHECK_EQUAL(x.rfind("bc", 2, 10), y.rfind("bc", 2, 10));
}
CAF_TEST(find_first_of) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find_first_of('a'), y.find_first_of('a'));
CAF_CHECK_EQUAL(x.find_first_of('b'), y.find_first_of('b'));
CAF_CHECK_EQUAL(x.find_first_of('g'), y.find_first_of('g'));
CAF_CHECK_EQUAL(x.find_first_of('a', 1), y.find_first_of('a', 1));
CAF_CHECK_EQUAL(x.find_first_of("a"), y.find_first_of("a"));
CAF_CHECK_EQUAL(x.find_first_of("bc"), y.find_first_of("bc"));
CAF_CHECK_EQUAL(x.find_first_of("ce"), y.find_first_of("ce"));
CAF_CHECK_EQUAL(x.find_first_of("bc", 1), y.find_first_of("bc", 1));
CAF_CHECK_EQUAL(x.find_first_of("bc", 1, 0), y.find_first_of("bc", 1, 0));
CAF_CHECK_EQUAL(x.find_first_of("bc", 0, 1), y.find_first_of("bc", 0, 1));
CAF_CHECK_EQUAL(x.find_first_of("bc", 2, 10), y.find_first_of("bc", 2, 10));
}
CAF_TEST(find_last_of) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find_last_of('a'), y.find_last_of('a'));
CAF_CHECK_EQUAL(x.find_last_of('b'), y.find_last_of('b'));
CAF_CHECK_EQUAL(x.find_last_of('g'), y.find_last_of('g'));
CAF_CHECK_EQUAL(x.find_last_of('a', 1), y.find_last_of('a', 1));
CAF_CHECK_EQUAL(x.find_last_of("a"), y.find_last_of("a"));
CAF_CHECK_EQUAL(x.find_last_of("bc"), y.find_last_of("bc"));
CAF_CHECK_EQUAL(x.find_last_of("ce"), y.find_last_of("ce"));
CAF_CHECK_EQUAL(x.find_last_of("bc", 1), y.find_last_of("bc", 1));
CAF_CHECK_EQUAL(x.find_last_of("bc", 1, 0), y.find_last_of("bc", 1, 0));
CAF_CHECK_EQUAL(x.find_last_of("bc", 0, 1), y.find_last_of("bc", 0, 1));
CAF_CHECK_EQUAL(x.find_last_of("bc", 2, 10), y.find_last_of("bc", 2, 10));
}
CAF_TEST(find_first_not_of) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find_first_not_of('a'), y.find_first_not_of('a'));
CAF_CHECK_EQUAL(x.find_first_not_of('b'), y.find_first_not_of('b'));
CAF_CHECK_EQUAL(x.find_first_not_of('g'), y.find_first_not_of('g'));
CAF_CHECK_EQUAL(x.find_first_not_of('a', 1), y.find_first_not_of('a', 1));
CAF_CHECK_EQUAL(x.find_first_not_of("a"), y.find_first_not_of("a"));
CAF_CHECK_EQUAL(x.find_first_not_of("bc"), y.find_first_not_of("bc"));
CAF_CHECK_EQUAL(x.find_first_not_of("ce"), y.find_first_not_of("ce"));
CAF_CHECK_EQUAL(x.find_first_not_of("bc", 1), y.find_first_not_of("bc", 1));
CAF_CHECK_EQUAL(x.find_first_not_of("bc", 1, 0),
y.find_first_not_of("bc", 1, 0));
CAF_CHECK_EQUAL(x.find_first_not_of("bc", 0, 1),
y.find_first_not_of("bc", 0, 1));
CAF_CHECK_EQUAL(x.find_first_not_of("bc", 2, 10),
y.find_first_not_of("bc", 2, 10));
}
CAF_TEST(find_last_not_of) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find_last_not_of('a'), y.find_last_not_of('a'));
CAF_CHECK_EQUAL(x.find_last_not_of('b'), y.find_last_not_of('b'));
CAF_CHECK_EQUAL(x.find_last_not_of('g'), y.find_last_not_of('g'));
CAF_CHECK_EQUAL(x.find_last_not_of('a', 1), y.find_last_not_of('a', 1));
CAF_CHECK_EQUAL(x.find_last_not_of("a"), y.find_last_not_of("a"));
CAF_CHECK_EQUAL(x.find_last_not_of("bc"), y.find_last_not_of("bc"));
CAF_CHECK_EQUAL(x.find_last_not_of("ce"), y.find_last_not_of("ce"));
CAF_CHECK_EQUAL(x.find_last_not_of("bc", 1), y.find_last_not_of("bc", 1));
CAF_CHECK_EQUAL(x.find_last_not_of("bc", 1, 0),
y.find_last_not_of("bc", 1, 0));
CAF_CHECK_EQUAL(x.find_last_not_of("bc", 0, 1),
y.find_last_not_of("bc", 0, 1));
CAF_CHECK_EQUAL(x.find_last_not_of("bc", 2, 10),
y.find_last_not_of("bc", 2, 10));
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment