Skip to content

Commit

Permalink
Clean up how const types are handled and fix C-style arrays. Fixes #19,
Browse files Browse the repository at this point in the history
fixes #20, fixes #21
  • Loading branch information
calebzulawski committed Oct 14, 2019
1 parent dae6eda commit 207e0e6
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 29 deletions.
9 changes: 9 additions & 0 deletions include/hippo/detail/base.h
Expand Up @@ -68,6 +68,15 @@ struct configuration {
//! for optionally making SFINAE possible.
template <typename T, typename U = T> struct printer;

//! Specialization for printing const types
template <typename T> struct printer<const T> : hippo::printer<T> {};

//! Specialization for printing volatile types
template <typename T> struct printer<volatile T> : hippo::printer<T> {};

//! Specialization for printing const volatile types
template <typename T> struct printer<const volatile T> : hippo::printer<T> {};

namespace detail {
struct print_visitor {
std::vector<std::string> operator()(const ::hippo::line &line) {
Expand Down
2 changes: 1 addition & 1 deletion include/hippo/detail/builtin/array.h
Expand Up @@ -10,7 +10,7 @@ namespace hippo {
template <typename T, std::size_t N>
struct printer<T[N]> : detail::arraylike_base<T[N], printer<T[N]>> {
//!@cond
constexpr static const char *prefix = "native array [";
constexpr static const char *prefix = "native array";
//!@endcond
};

Expand Down
42 changes: 40 additions & 2 deletions include/hippo/detail/builtin/numbers.h
Expand Up @@ -8,10 +8,44 @@

namespace hippo {

template <> struct printer<char> {
using format_type = ::hippo::integer_format;
static ::hippo::object print(const char &t, std::uint64_t current_indent,
const ::hippo::configuration &,
const format_type &format = format_type()) {
return ::hippo::object{std::in_place_type<::hippo::line>, current_indent,
::hippo::apply_format(int(t), format)};
}
};

template <> struct printer<unsigned char> {
using format_type = ::hippo::integer_format;
static ::hippo::object print(const unsigned char &t,
std::uint64_t current_indent,
const ::hippo::configuration &,
const format_type &format = format_type()) {
return ::hippo::object{std::in_place_type<::hippo::line>, current_indent,
::hippo::apply_format(int(t), format)};
}
};

template <> struct printer<signed char> {
using format_type = ::hippo::integer_format;
static ::hippo::object print(const signed char &t,
std::uint64_t current_indent,
const ::hippo::configuration &,
const format_type &format = format_type()) {
return ::hippo::object{std::in_place_type<::hippo::line>, current_indent,
::hippo::apply_format(int(t), format)};
}
};

//!\cond
template <typename T>
struct printer<
T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, T>> {
T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool> &&
!std::is_const_v<T> && !std::is_volatile_v<T>,
T>> {
using format_type = ::hippo::integer_format;
static ::hippo::object print(const T &t, std::uint64_t current_indent,
const ::hippo::configuration &,
Expand All @@ -22,7 +56,10 @@ struct printer<
};

template <typename T>
struct printer<T, std::enable_if_t<std::is_floating_point_v<T>, T>> {
struct printer<
T, std::enable_if_t<std::is_floating_point_v<T> && !std::is_const_v<T> &&
!std::is_volatile_v<T>,
T>> {
using format_type = ::hippo::float_format;
static ::hippo::object print(const T &t, std::uint64_t current_indent,
const ::hippo::configuration &,
Expand All @@ -33,6 +70,7 @@ struct printer<T, std::enable_if_t<std::is_floating_point_v<T>, T>> {
};

template <> struct printer<bool> {
using format_type = ::hippo::no_format;
static ::hippo::object print(const bool &b, std::uint64_t current_indent,
const ::hippo::configuration &) {
return ::hippo::object{std::in_place_type<::hippo::line>, current_indent,
Expand Down
47 changes: 21 additions & 26 deletions include/hippo/detail/containers.h
Expand Up @@ -3,6 +3,7 @@

#include "base.h"
#include "formatter.h"
#include <iterator>
#include <utility>

namespace hippo {
Expand All @@ -15,28 +16,26 @@ using map_format = std::pair<typename ::hippo::printer<Key>::format_type,
namespace detail {

template <typename Container, typename Base> struct arraylike_base {
using printer_type = ::hippo::printer<std::remove_cv_t<
std::remove_reference_t<decltype(*std::declval<Container>().begin())>>>;
using printer_type = ::hippo::printer<typename std::iterator_traits<decltype(
std::begin(std::declval<Container &>()))>::value_type>;
using format_type = typename printer_type::format_type;
static ::hippo::object print(const Container &c, std::uint64_t current_indent,
const ::hippo::configuration &config,
const format_type &format = format_type()) {
std::list<::hippo::object> objects;
if (c.empty()) {
if (std::begin(c) == std::end(c)) {
objects.emplace_back(std::in_place_type<::hippo::line>, current_indent,
std::string(Base::prefix) + " [empty]");
} else {
objects.emplace_back(std::in_place_type<::hippo::line>, current_indent,
std::string(Base::prefix) + " [");
if (c.begin() != c.end()) {
objects.push_back(printer_type::print(*c.begin(), current_indent + 1,
config, format));
auto end = c.end();
for (auto it = std::next(c.begin()); it != end; ++it) {
std::visit(::hippo::append_visitor{","}, objects.back());
objects.push_back(
printer_type::print(*it, current_indent + 1, config, format));
}
objects.push_back(printer_type::print(*std::begin(c), current_indent + 1,
config, format));
auto end = std::end(c);
for (auto it = std::next(std::begin(c)); it != end; ++it) {
std::visit(::hippo::append_visitor{","}, objects.back());
objects.push_back(
printer_type::print(*it, current_indent + 1, config, format));
}
objects.emplace_back(std::in_place_type<::hippo::line>, current_indent,
"]");
Expand All @@ -46,9 +45,10 @@ template <typename Container, typename Base> struct arraylike_base {
};

template <typename Container, typename Base> struct maplike_base {
using format_type =
map_format<decltype(std::declval<Container>().begin()->first),
decltype(std::declval<Container>().begin()->second)>;
using value_type = typename std::iterator_traits<decltype(
std::begin(std::declval<Container>()))>::value_type;
using format_type = map_format<typename value_type::first_type,
typename value_type::second_type>;
static ::hippo::object print(const Container &c, std::uint64_t current_indent,
const ::hippo::configuration &config,
const format_type &format = format_type()) {
Expand All @@ -66,22 +66,17 @@ template <typename Container, typename Base> struct maplike_base {
current_indent + 1, "(");

// key
auto key_subobject = ::hippo::printer<std::remove_cv_t<
std::remove_reference_t<decltype(key)>>>::print(key,
current_indent + 2,
config,
format.first);
auto key_subobject =
::hippo::printer<std::remove_reference_t<decltype(key)>>::print(
key, current_indent + 2, config, format.first);
std::visit(::hippo::prepend_visitor{"key: "}, key_subobject);
std::visit(::hippo::append_visitor{","}, key_subobject);
subobjects.push_back(key_subobject);

// value
auto value_subobject = ::hippo::printer<std::remove_cv_t<
std::remove_reference_t<decltype(value)>>>::print(value,
current_indent +
2,
config,
format.second);
auto value_subobject =
::hippo::printer<std::remove_reference_t<decltype(value)>>::print(
value, current_indent + 2, config, format.second);
std::visit(::hippo::prepend_visitor{"value: "}, value_subobject);
subobjects.push_back(value_subobject);

Expand Down
27 changes: 27 additions & 0 deletions test/base/array.cpp
@@ -0,0 +1,27 @@
#include "arraylike.h"
#include "hippo/hippo.h"

TEST_CASE("native array") {
hippo::configuration config;
config.indent = 2;
int val[]{0, 1, 2};
SECTION("expanded") {
config.width = 0;
std::vector<std::string> expected_string{"native array [", " 0,", " 1,",
" 2", "]"};
REQUIRE(hippo::print(val, config) == expected_string);
}
SECTION("compressed") {
config.width = 100;
std::vector<std::string> expected_string{"native array [ 0, 1, 2 ]"};
REQUIRE(hippo::print(val, config) == expected_string);
}
SECTION("formatted") {
config.width = 100;
hippo::integer_format fmt;
fmt.base = hippo::integer_format::base_type::hex;
std::vector<std::string> expected_string{"native array [ 0x0, 0x1, 0x2 ]"};
REQUIRE(hippo::print(hippo::formatter(val, fmt), config) ==
expected_string);
}
}
23 changes: 23 additions & 0 deletions test/base/const.cpp
@@ -0,0 +1,23 @@
#include "catch.hpp"
#include "hippo/hippo.h"

struct Foo {};

HIPPO_CLASS_BEGIN(Foo);
HIPPO_CLASS_END();

TEST_CASE("const volatile type") {
hippo::configuration config;
config.indent = 2;
Foo foo;
std::string expected("Foo { }");
REQUIRE(
std::get<hippo::line>(hippo::printer<const Foo>::print(foo, 0, config))
.string == expected);
REQUIRE(
std::get<hippo::line>(hippo::printer<volatile Foo>::print(foo, 0, config))
.string == expected);
REQUIRE(std::get<hippo::line>(
hippo::printer<const volatile Foo>::print(foo, 0, config))
.string == expected);
}
56 changes: 56 additions & 0 deletions test/base/number.cpp
@@ -0,0 +1,56 @@
#include "catch.hpp"
#include "hippo/hippo.h"

TEMPLATE_TEST_CASE("integer", "[builtin]", std::uint8_t, std::uint16_t,
std::uint32_t, std::uint64_t, std::int8_t, std::int16_t,
std::int32_t, std::int64_t) {
TestType value = 2;
hippo::configuration config;
SECTION("decimal") {
std::vector<std::string> expected{"2"};
REQUIRE(hippo::print(value, config) == expected);
}
SECTION("octal") {
hippo::integer_format fmt;
fmt.base = hippo::integer_format::base_type::oct;
std::vector<std::string> expected{"02"};
REQUIRE(hippo::print(hippo::formatter(value, fmt), config) == expected);
}
SECTION("hexadecimal") {
hippo::integer_format fmt;
fmt.base = hippo::integer_format::base_type::hex;
std::vector<std::string> expected{"0x2"};
REQUIRE(hippo::print(hippo::formatter(value, fmt), config) == expected);
}
}

TEMPLATE_TEST_CASE("float", "[builtin]", float, double, long double) {
TestType value = 0.5;
hippo::configuration config;
SECTION("default") {
std::vector<std::string> expected{"0.5"};
REQUIRE(hippo::print(value, config) == expected);
}
SECTION("scientific") {
hippo::float_format fmt;
fmt.notation = hippo::float_format::notation_type::scientific;
fmt.precision = 2;
std::vector<std::string> expected{"5.00e-01"};
REQUIRE(hippo::print(hippo::formatter(value, fmt), config) == expected);
}
SECTION("fixed") {
hippo::float_format fmt;
fmt.notation = hippo::float_format::notation_type::fixed;
fmt.precision = 2;
std::vector<std::string> expected{"0.50"};
REQUIRE(hippo::print(hippo::formatter(value, fmt), config) == expected);
}
}

TEST_CASE("bool") {
hippo::configuration config;
std::vector<std::string> expected_false{"false"};
std::vector<std::string> expected_true{"true"};
REQUIRE(hippo::print(false, config) == expected_false);
REQUIRE(hippo::print(true, config) == expected_true);
}
17 changes: 17 additions & 0 deletions test/std/map.cpp
Expand Up @@ -47,3 +47,20 @@ using multimap_type = std::multimap<int, float>;

MAKE_TEST("map", "std::map", map_type)
MAKE_TEST("multimap", "std::multimap", multimap_type)

// Keys are const, so make sure this works
enum class MapFoo { Bar };

HIPPO_ENUM_BEGIN(MapFoo)
HIPPO_ENUM_VALUE(MapFoo::Bar)
HIPPO_ENUM_END()

TEST_CASE("map with enum key") {
std::map<MapFoo, MapFoo> m;
m[MapFoo::Bar] = MapFoo::Bar;
hippo::configuration config;
config.width = 100;
std::vector<std::string> expected{
"std::map [ ( key: enum MapFoo [Bar], value: enum MapFoo [Bar] ) ]"};
REQUIRE(hippo::print(m, config) == expected);
}

0 comments on commit 207e0e6

Please sign in to comment.