Skip to content

Commit

Permalink
replace mapbox/variant.hpp in feature.hpp
Browse files Browse the repository at this point in the history
  • Loading branch information
louwers committed Oct 16, 2024
1 parent 1297004 commit 552a2b0
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 60 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.30)
project(hpp_skel LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED on)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Expand Down
142 changes: 102 additions & 40 deletions include/maplibre/feature.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

#include <maplibre/geometry.hpp>

#include <mapbox/variant.hpp>

#include <cstdint>
#include <string>
#include <variant>
#include <vector>
#include <memory>
#include <unordered_map>
Expand Down Expand Up @@ -49,25 +48,25 @@ constexpr bool operator<(const null_value_t&, const null_value_t&) { return fals

constexpr null_value_t null_value = null_value_t();

#define DECLARE_VALUE_TYPE_ACCESOR(NAME, TYPE) \
TYPE* get##NAME() noexcept \
{ \
return match( \
[](TYPE& val) -> TYPE* { return &val; }, \
[](auto&) -> TYPE* { return nullptr; }); \
} \
const TYPE* get##NAME() const noexcept \
{ \
return const_cast<value*>(this)->get##NAME(); \
}
// helper class for std::visit
namespace {
template <class... Ts>
struct overloaded : Ts...
{
using Ts::operator()...;
};
}; // namespace

struct value;

// Multiple numeric types (uint64_t, int64_t, double) are present in order to support
// the widest possible range of JSON numbers, which do not have a maximum range.
// Implementations that produce `value`s should use that order for type preference,
// using uint64_t for positive integers, int64_t for negative integers, and double
// for non-integers and integers outside the range of 64 bits.
using value_base = mapbox::util::variant<null_value_t, bool, uint64_t, int64_t, double, std::string,
std::shared_ptr<std::vector<value>>,
std::shared_ptr<std::unordered_map<std::string, value>>>;
using value_base = std::variant<null_value_t, bool, uint64_t, int64_t, double, std::string,
std::shared_ptr<std::vector<value>>,
std::shared_ptr<std::unordered_map<std::string, value>>>;

struct value : public value_base
{
Expand Down Expand Up @@ -105,54 +104,117 @@ struct value : public value_base
value(object_type object) : value_base(std::make_shared<object_type>(std::forward<object_type>(object))) {}
value(object_ptr_type object) : value_base(object) {}

bool operator==(value const& rhs) const
{
assert(valid() && rhs.valid());
if (this->which() != rhs.which())
{
return false;
}
mapbox::util::detail::comparer<value, equal_comp_shared_ptr> visitor(*this);
return visit(rhs, visitor);
}

explicit operator bool() const { return !is<null_value_t>(); }
explicit operator bool() const { return !std::holds_alternative<null_value_t>(variant()); }

DECLARE_VALUE_TYPE_ACCESOR(Int, int64_t)
DECLARE_VALUE_TYPE_ACCESOR(Uint, uint64_t)
DECLARE_VALUE_TYPE_ACCESOR(Bool, bool)
DECLARE_VALUE_TYPE_ACCESOR(Double, double)
DECLARE_VALUE_TYPE_ACCESOR(String, std::string)
// TODO: allow comparing values held by shared ptrs
friend bool operator==(const value&, const value&) = default;

array_ptr_type getArray() noexcept
{
return match(
[](array_ptr_type& val) -> array_ptr_type { return val; },
[](auto&) -> array_ptr_type { return nullptr; });
return std::visit(overloaded{
[](array_ptr_type& val) -> array_ptr_type { return val; },
[](auto&) -> array_ptr_type { return nullptr; }},
variant());
}

const_array_ptr_type getArray() const noexcept
{
return const_cast<value*>(this)->getArray();
}

object_ptr_type getObject() noexcept
{
return match(
[](object_ptr_type& val) -> object_ptr_type { return val; },
[](auto&) -> object_ptr_type { return nullptr; });
return std::visit(overloaded{
[](object_ptr_type& val) -> object_ptr_type { return val; },
[](auto&) -> object_ptr_type { return nullptr; }},
variant());
}

const_object_ptr_type getObject() const noexcept
{
return const_cast<value*>(this)->getObject();
}

value_base& variant()
{
return *static_cast<value_base*>(this);
}

value_base const& variant() const
{
return *static_cast<const value_base*>(this);
}

int64_t* getInt() noexcept
{
return std::visit(overloaded{
[](int64_t& val) -> int64_t* { return &val; },
[](auto&) -> int64_t* { return nullptr; }},
variant());
}

const int64_t* getInt() const noexcept
{
return const_cast<value*>(this)->getInt();
}

uint64_t* getUint() noexcept
{
return std::visit(overloaded{
[](uint64_t& val) -> uint64_t* { return &val; },
[](auto&) -> uint64_t* { return nullptr; }},
variant());
}

const uint64_t* getUint() const noexcept
{
return const_cast<value*>(this)->getUint();
}

bool* getBool() noexcept
{
return std::visit(overloaded{
[](bool& val) -> bool* { return &val; },
[](auto&) -> bool* { return nullptr; }},
variant());
}

const bool* getBool() const noexcept
{
return const_cast<value*>(this)->getBool();
}
double* getDouble() noexcept
{
return std::visit(overloaded{
[](double& val) -> double* { return &val; },
[](auto&) -> double* { return nullptr; }},
variant());
}

const double* getDouble() const noexcept
{
return const_cast<value*>(this)->getDouble();
}
std::string* getString() noexcept
{
return std::visit(overloaded{
[](std::string& val) -> std::string* { return &val; },
[](auto&) -> std::string* { return nullptr; }},
variant());
}

const std::string* getString() const noexcept
{
return const_cast<value*>(this)->getString();
}
};

#undef DECLARE_VALUE_TYPE_ACCESOR

using property_map = value::object_type;

// The same considerations and requirement for numeric types apply as for `value_base`.
using identifier = mapbox::util::variant<null_value_t, uint64_t, int64_t, double, std::string>;
using identifier = std::variant<null_value_t, uint64_t, int64_t, double, std::string>;

template <class T>
struct feature
Expand Down
8 changes: 4 additions & 4 deletions include/maplibre/geometry_io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ struct value_to_stream_visitor
{
out << ',';
}
mapbox::util::apply_visitor(*this, item);
std::visit(*this, item);
}
out << ']';
}
Expand Down Expand Up @@ -181,7 +181,7 @@ struct value_to_stream_visitor
auto const val = map.find(k);
quote_string(k, out);
out << ':';
mapbox::util::apply_visitor(*this, val->second);
std::visit(*this, val->second);
}
out << '}';
}
Expand All @@ -208,7 +208,7 @@ inline std::ostream& operator<<(std::ostream& os, std::vector<maplibre::feature:

inline std::ostream& operator<<(std::ostream& os, maplibre::feature::value const& val)
{
mapbox::util::apply_visitor(value_to_stream_visitor{os}, val);
std::visit(value_to_stream_visitor{os}, val);
return os;
}

Expand All @@ -231,7 +231,7 @@ struct identifier_to_stream_visitor

inline std::ostream& operator<<(std::ostream& os, maplibre::feature::identifier const& val)
{
mapbox::util::apply_visitor(identifier_to_stream_visitor{os}, val);
std::visit(identifier_to_stream_visitor{os}, val);
return os;
}

Expand Down
31 changes: 16 additions & 15 deletions test/feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ try
{
value v{arg};
CHECK(v);
CHECK(v.template is<T>());
CHECK(v.template get<T>() == arg);
CHECK(std::holds_alternative<T>(v));
CHECK(std::get<T>(v) == arg);
}
catch (...)
{
Expand All @@ -31,8 +31,8 @@ try
{
value v{arg};
CHECK(v);
CHECK(v.template is<T>());
CHECK(*(v.template get<T>()) == *arg);
CHECK(std::holds_alternative<T>(v));
CHECK(*(std::get<T>(v)) == *arg);
}
catch (...)
{
Expand All @@ -45,8 +45,8 @@ try
{
value v{arg};
CHECK(v);
CHECK(v.template is<T>());
CHECK(*(v.template get<T>()) == arg);
CHECK(std::holds_alternative<T>(v));
CHECK(*(std::get<T>(v)) == arg);
}
catch (...)
{
Expand All @@ -73,13 +73,13 @@ TEST_CASE("test value")
checkPtrType2<value::object_ptr_type>(map);

value intV{32};
CHECK_THROWS(intV.get<uint64_t>());
CHECK_THROWS(std::get<uint64_t>(intV));

auto* result = intV.getInt();
CHECK(result);
CHECK(*result == 32);
*result = 100;
CHECK(intV.get<int64_t>() == 100);
CHECK(std::get<int64_t>(intV) == 100);

CHECK_FALSE(intV.getUint());
CHECK_FALSE(intV.getBool());
Expand All @@ -104,21 +104,22 @@ TEST_CASE("test feature")
p["int"] = int64_t(-10);
p["null"] = null_value;

REQUIRE(p["bool"].is<bool>());
REQUIRE(std::holds_alternative<bool>(p["bool"]));
CHECK(p["bool"] == true);
REQUIRE(p["string"].is<std::string>());
REQUIRE(std::holds_alternative<std::string>(p["string"]));
CHECK(p["string"] == std::string("foo"));
REQUIRE(p["double"].is<double>());
REQUIRE(std::holds_alternative<double>(p["double"]));
CHECK(p["double"] == 2.5);
REQUIRE(p["uint"].is<uint64_t>());
REQUIRE(std::holds_alternative<uint64_t>(p["uint"]));
CHECK(p["uint"] == uint64_t(10));
REQUIRE(p["int"].is<int64_t>());
REQUIRE(std::holds_alternative<int64_t>(p["int"]));
CHECK(p["int"] == int64_t(-10));
REQUIRE(p["null"].is<null_value_t>());
REQUIRE(std::holds_alternative<null_value_t>(p["null"]));
CHECK(p["null"] == null_value);

p["null"] = null_value_t{};
REQUIRE(p["null"].is<null_value_t>());
REQUIRE(std::holds_alternative<null_value_t>(p["null"]));

CHECK(p["null"] == null_value);

CHECK(p == p);
Expand Down

0 comments on commit 552a2b0

Please sign in to comment.