Skip to content

Commit

Permalink
Merge pull request LaboratoryOfPlasmaPhysics#13 from Dekken/const
Browse files Browse the repository at this point in the history
pure const dict access method
  • Loading branch information
PhilipDeegan authored Oct 14, 2020
2 parents 5b4be6c + 6c2bc09 commit dced0d9
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 29 deletions.
34 changes: 26 additions & 8 deletions include/dict.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@

namespace cppdict
{
namespace {
namespace
{
template<typename T1, typename... T2>
constexpr bool is_any_of()
{
return std::disjunction_v<std::is_same<T1, T2>...>;
}
}
} // namespace

namespace // Visitor details
{
Expand Down Expand Up @@ -103,8 +104,9 @@ struct Dict
using data_t = std::variant<empty_leaf_t, node_t, Types...>;

template<typename T>
struct is_value : std::conditional<!std::is_same_v<T, empty_leaf_t> and !std::is_same_v<T, node_t>,
std::true_type, std::false_type>::type
struct is_value
: std::conditional<!std::is_same_v<T, empty_leaf_t> and !std::is_same_v<T, node_t>,
std::true_type, std::false_type>::type
{
};
template<typename T>
Expand All @@ -131,6 +133,7 @@ struct Dict
return *this;
}
Dict& operator=(Dict&& other) = default;

Dict& operator[](const std::string& key)
{
#ifndef NDEBUG
Expand Down Expand Up @@ -161,6 +164,24 @@ struct Dict
}


Dict& operator[](const std::string& key) const
{
if (isNode())
{
auto& map = std::get<node_t>(data);

if (std::end(map) == map.find(key))
{
throw std::runtime_error("cppdict: invalid key: " + key);
}

return *std::get<node_t>(data).at(key);
}

throw std::runtime_error("cppdict: invalid key: " + key);
}


bool isLeaf() const noexcept { return !isNode() && !isEmpty(); }

bool isNode() const noexcept { return std::holds_alternative<node_t>(data); }
Expand Down Expand Up @@ -206,10 +227,7 @@ struct Dict
throw std::runtime_error("cppdict: not a map or not default");
}

bool contains(std::string key)
{
return isNode() and std::get<node_t>(data).count(key);
}
bool contains(std::string key) { return isNode() and std::get<node_t>(data).count(key); }

std::size_t size() const noexcept
{
Expand Down
56 changes: 35 additions & 21 deletions test/basic_dict_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ TEST_CASE("Can (depp)copy nodes with operator=", "[simple cppdict::Dict<int, dou
{
Dict dict;
dict["this"]["is"]["the"]["source"] = 3.14;
dict["destination"] = dict["this"];
REQUIRE(dict["destination"]["is"]["the"]["source"].to<double>()==3.14);
dict["destination"] = dict["this"];
REQUIRE(dict["destination"]["is"]["the"]["source"].to<double>() == 3.14);
}

TEST_CASE("Can add values and retrieve them", "[simple cppdict::Dict<int, double, std::string>]")
{
Dict dict;
dict["first"] = 3.14;
dict["first"] = 3.14;
dict["second"] = 1;
dict["third"] = std::string{"hello"};
dict["third"] = std::string{"hello"};
SECTION("Added values should be retrievable")
{
REQUIRE(dict["first"].to<double>() == 3.14);
Expand All @@ -40,43 +40,43 @@ TEST_CASE("Can add values and retrieve them", "[simple cppdict::Dict<int, double
}
}

TEST_CASE("Deals with both references and values", "[simple cppdict::Dict<int, double, std::string>]")
TEST_CASE("Deals with both references and values",
"[simple cppdict::Dict<int, double, std::string>]")
{
Dict dict;
dict["0"]["1"] = 3.5;
dict["0"]["2"]["1"] = 55.;
dict["0"]["2"]["2"] = 56.;
dict["0"]["1"] = 3.5;
dict["0"]["2"]["1"] = 55.;
dict["0"]["2"]["2"] = 56.;
dict["0"]["2"]["3"]["1"]["1"] = 666.;
SECTION("Values acces by value does a copy")
{
auto v = dict["0"]["1"].to<double>();
v = 10.;
REQUIRE(v!=dict["0"]["1"].to<double>());
v = 10.;
REQUIRE(v != dict["0"]["1"].to<double>());
}
SECTION("Values access by ref doesn't copy")
{
auto &v = dict["0"]["1"].to<double>();
v = 10.;
REQUIRE(v==dict["0"]["1"].to<double>());
auto& v = dict["0"]["1"].to<double>();
v = 10.;
REQUIRE(v == dict["0"]["1"].to<double>());
}
SECTION("Nodes access by value does copy")
{
auto node = dict["0"];
node["1"] = 100;
REQUIRE(dict["0"]["1"].to<double>()==3.5);
node = dict["2"];
REQUIRE(dict["0"]["1"].to<double>() == 3.5);
node = dict["2"];
node["3"]["1"]["1"] = 42;
REQUIRE(dict["0"]["2"]["3"]["1"]["1"].to<double>()==666.);
REQUIRE(dict["0"]["2"]["3"]["1"]["1"].to<double>() == 666.);
}
SECTION("Nodes access by ref doesn't copy")
{
auto &node = dict["0"];
node["1"] = 100;
auto& node = dict["0"];
node["1"] = 100;
node["2"]["3"]["1"]["1"] = 42;
REQUIRE(dict["0"]["1"].to<int>()==100);
REQUIRE(dict["0"]["2"]["3"]["1"]["1"].to<int>()==42);
REQUIRE(dict["0"]["1"].to<int>() == 100);
REQUIRE(dict["0"]["2"]["3"]["1"]["1"].to<int>() == 42);
}

}


Expand All @@ -90,3 +90,17 @@ TEST_CASE("Contains expects true or false", "[simple cppdict::Dict<int, double,
REQUIRE(dict["this"]["is"]["the"].contains("source"));
REQUIRE(!dict["this"]["is"]["the"]["source"].contains("nothing"));
}


TEST_CASE("Dict const accessor", "[simple cppdict::Dict<int>]")
{
Dict dict;
dict["first"] = 3.14;
dict["second"]["third"] = 3;

auto const& dictRef = dict;

REQUIRE(dictRef["first"].to<double>() == 3.14);
REQUIRE_THROWS_WITH(dictRef["second"].to<double>(), "cppdict: to<T> invalid type");
REQUIRE_THROWS_WITH(dictRef["one"]["two"].to<double>(), "cppdict: invalid key: one");
}

0 comments on commit dced0d9

Please sign in to comment.