Skip to content

Commit

Permalink
consistent API
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilipDeegan authored and jeandet committed Feb 6, 2024
1 parent 7fb589e commit f0e1fb0
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 54 deletions.
78 changes: 33 additions & 45 deletions include/dict.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,81 +338,69 @@ struct Dict
}
};

namespace detail
{
auto split_string(std::string const& path, char delimiter = '/')
{
std::vector<std::string> keys;
std::string key;
std::istringstream tokenStream{path};
while (std::getline(tokenStream, key, delimiter))
keys.push_back(key);
return keys;
}
} // namespace detail



template<typename... Types>
auto& get(std::vector<std::string> keys, size_t iKey, Dict<Types...>& currentNode)
auto& get(std::vector<std::string> const& keys, size_t iKey, Dict<Types...>& currentNode)
{
if (iKey == keys.size() - 1)
return currentNode[keys[iKey]];

return get(keys, iKey + 1, currentNode[keys[iKey]]);
}


auto _split_string(std::string const& path, char delimiter = '/')
template<typename... Types>
std::optional<Dict<Types...>> get(std::vector<std::string> const& keys, size_t iKey,
Dict<Types...> const& currentNode)
{
std::vector<std::string> keys;
std::string key;
std::istringstream tokenStream{path};
while (std::getline(tokenStream, key, delimiter))
keys.push_back(key);
return keys;
if (currentNode.contains(keys[iKey]))
{
auto const& next = currentNode[keys[iKey]];
if (iKey == keys.size() - 1)
return next;
return get(keys, ++iKey, next);
}
return std::nullopt;
}


template<typename T, template<typename... Types> class Dict, typename... Types,
typename Check = std::enable_if_t<is_any_of<T, Types...>()>>
void add(std::string path, T&& value, Dict<Types...>& dict)
{
auto keys = _split_string(path);
auto keys = detail::split_string(path);
auto&& node = get(keys, 0ul, dict);
node = std::forward<T>(value);
}


template<typename Paths, typename... Types>
std::optional<Dict<Types...>> _traverse_to_node(Dict<Types...> const& dict, Paths const& paths,
std::size_t idx = 0)
{
if (dict.contains(paths[idx]))
{
auto const& next = dict[paths[idx]];
if (idx == paths.size() - 1)
return next;
return _traverse_to_node(next, paths, ++idx);
}
return std::nullopt;
}


template<typename... Types>
std::optional<Dict<Types...>> traverse_to_node(Dict<Types...> const& dict, std::string const& path,
char delimiter = '/')
{
auto paths = _split_string(path);
return _traverse_to_node(dict, paths);
}


template<typename T, typename... Types>
T const& at(Dict<Types...> const& dict, std::string const& path, char delimiter = '/')
T get_value(Dict<Types...> const& dict, std::vector<std::string> const& paths,
T const default_value)
{
auto leaf = traverse_to_node(dict, path, delimiter);
if (leaf)
if (auto leaf = get(paths, 0, dict))
return leaf->template to<T>();
throw std::runtime_error("cppdict: contains no path " + path);
return default_value;
}


template<typename T, typename... Types>
T at(Dict<Types...> const& dict, std::string const& path, T const default_value,
char delimiter = '/')
T get_value(Dict<Types...> const& dict, std::string const& path, T const default_value,
char delimiter = '/')
{
auto leaf = traverse_to_node(dict, path, delimiter);
if (leaf)
return leaf->template to<T>();
return default_value;
return get_value(dict, detail::split_string(path), default_value);
}


Expand Down
12 changes: 3 additions & 9 deletions test/basic_dict_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,11 @@ TEST_CASE("Dict const accessor", "[simple cppdict::Dict<int>]")
REQUIRE_THROWS_WITH(dictRef["one"]["two"].to<double>(), "cppdict: invalid key: one");
}

TEST_CASE("Can at key by delimiter if exists", "or raises if missing")
{
Dict dict;
dict["this"]["is"]["pi"] = 3.14;
REQUIRE_THROWS_WITH(cppdict::at<double>(dict, "this/is/e"),
"cppdict: contains no path this/is/e");
}

TEST_CASE("Can at key by delimiter if exists", "or default if missing")

TEST_CASE("Can get_value key by delimiter if exists", "or default if missing")
{
Dict dict;
dict["this"]["is"]["pi"] = 3.14;
REQUIRE(cppdict::at(dict, "this/is/e", 2.71) == 2.71);
REQUIRE(cppdict::get_value(dict, "this/is/e", 2.71) == 2.71);
}

0 comments on commit f0e1fb0

Please sign in to comment.