Skip to content

Instantly share code, notes, and snippets.

@ldionne
Created March 2, 2017 17:15
Show Gist options
  • Save ldionne/43bcc54bd4004ebf58f900ecf563e821 to your computer and use it in GitHub Desktop.
Save ldionne/43bcc54bd4004ebf58f900ecf563e821 to your computer and use it in GitHub Desktop.
Library-based value-syntax for reflection as shown in Issaquah
//
// A demo of value-syntax reflection built on top of the current reflection proposal,
// as shown to the Reflection SG at the Issaquah meeting in 2016.
//
// Author: Louis Dionne
//
// ~/code/llvm/build/prefix/bin/clang++ -I ~/code/hana/include -isystem ~/code/llvm/build/prefix/lib/clang/4.0.0/include -I ~/code/llvm/tools/clang/reflection -Xclang -freflection -std=c++1z code/worksheet.cpp
#include <boost/hana.hpp>
#include <iostream>
#include <reflexpr>
#include <type_traits>
namespace hana = boost::hana;
using namespace hana::literals;
namespace meta = std::meta;
////////////////////////////////// SHIM //////////////////////////////////////
// Those are required to preserve instantiation laziness when using member functions.
template <typename T, typename ...>
struct get_size : meta::get_size<T> { };
template <typename T, std::size_t I, typename ...>
struct get_element : meta::get_element<T, I> { };
template <typename T, typename ...>
struct get_data_members : meta::get_data_members<T> { };
template <typename T, typename ...>
struct get_base_name : meta::get_base_name<T> { };
template <typename T, typename ...>
struct get_pointer : meta::get_pointer<T> { };
template <typename MetaObject>
struct reflexpr_wrapper;
template <typename MetaObjectSeq>
struct reflexpr_sequence_wrapper;
template <typename T>
constexpr auto reflexpr_ = reflexpr_wrapper<reflexpr(T)>{};
template <typename MetaObjectSeq>
struct reflexpr_sequence_wrapper {
template <typename ...Empty>
constexpr auto size() const {
return get_size<MetaObjectSeq, Empty...>{};
}
template <typename I>
constexpr auto operator[](I const&) const {
using Element = typename get_element<MetaObjectSeq, I::value>::type;
return reflexpr_wrapper<Element>{};
}
};
template <typename MetaObject>
struct reflexpr_wrapper {
template <typename ...Empty>
constexpr auto members() const {
using Members = typename get_data_members<MetaObject, Empty...>::type;
return reflexpr_sequence_wrapper<Members>{};
}
template <typename ...Empty>
constexpr auto name() const {
return get_base_name<MetaObject, Empty...>::value;
}
template <typename ...Empty>
constexpr auto pointer() const {
return get_pointer<MetaObject, Empty...>::value;
}
};
//////////////////////////////////////////////////////////////////////////////
#if 0
/////////////////// PROPOSED IMPLEMENTATION //////////////////////////////////
template <typename Metaobjects, std::size_t I, typename T>
void field_to_json(std::ostream& out, const T& v) {
using Member = std::meta::get_element_m<Metaobjects, I>;
if (I > 0) out << ", ";
out << '"' << std::meta::get_base_name_v<Member> << "\": ";
to_json(out, (v.*std::meta::get_pointer_v<Member>));
}
template <typename Metaobjects, std::size_t ...I, typename T>
void fields_to_json(std::ostream& out, T const& v,
std::index_sequence<I...>)
{
(field_to_json<Metaobjects, I>(out, v), ...);
}
template <typename T>
std::ostream& to_json(std::ostream& out, T const& v) {
typedef reflexpr(T) meta_T;
if constexpr (std::meta::Record<reflexpr(T)>{}) {
out << "{";
using Members = std::meta::get_data_members_m<reflexpr(T)>;
fields_to_json<Members>(out, v,
std::make_index_sequence<std::meta::get_size_v<Members>>{}
);
out << "}";
} else {
out << v;
}
}
//////////////////////////////////////////////////////////////////////////////
#endif
//////////////////////////////// HANA-STYLE /////////////////////////////////
template <typename T>
std::ostream& to_json(std::ostream& out, T const& v) {
if constexpr(std::meta::Record<reflexpr(T)>) {
out << "{";
auto members = reflexpr_<T>.members();
auto indices = hana::make_range(0_c, members.size());
hana::for_each(indices, [&](auto i) {
if (i > 0) out << ", ";
out << '"' << members[i].name() << "\": ";
to_json(out, v.*members[i].pointer());
});
out << '}';
} else {
out << v;
}
return out;
}
//////////////////////////////////////////////////////////////////////////////
struct point { float x, y, z; };
struct triangle { point a, b, c; };
struct tetrahedron {
triangle base;
point apex;
};
int main() {
tetrahedron t{
{{0.f,0.f,0.f}, {1.f,0.f,0.f}, {0.f,0.f,1.f}},
{0.f,1.f,0.f}
};
to_json(std::cout, t);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment