/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby,
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.
*******************************************************************************/
#include <stdio.h>
#include <type_traits>
#include <iostream>
#include "record.hpp"
#include "find_prop_type.hpp"
enum class f_int { v };
enum class f_float { v };
enum class f_str { v };
enum class f_rec { v };
enum class f_unknown { v };
enum class f_data {v};
enum class f_next {v};
using namespace tensors::type_map;
using namespace tensors::structural;
template <typename T>
struct ll_node
: virtual public record<prop<f_data, T>, prop<f_next, ll_node<T> *>>
{
ll_node()
{
(*this)[f_next::v] = nullptr;
}
};
int main()
{
using namespace std;
cout << "Looking for " << typeid(f_int).name() << endl;
using found1 =
find_prop_type<
f_int,
prop<f_int, int>,
prop<f_float, float>
>;
found1::print(std::cout);
cout << "Value type found: " << typeid(value_type_of<typename found1::prop_type>).name() << endl;
cout << endl;
cout << "Looking for " << typeid(f_float).name() << endl;
using found2 =
find_prop_type<
f_float,
prop<f_int, int>,
prop<f_float, float>
>;
found2::print(std::cout);
cout << "Value type found: " << typeid(value_type_of<typename found2::prop_type>).name() << endl;
cout << endl;
cout << "Looking for " << typeid(f_unknown).name() << endl;
using found3 =
find_prop_type<
f_unknown,
prop<f_int, int>,
prop<f_float, float>
>;
found3::print(std::cout);
cout << "Value type found: " << typeid(value_type_of<typename found3::prop_type>).name() << endl;
cout << endl;
record
<
prop<f_int, int>,
prop<f_float, float>,
prop
<
f_rec,
record
<
prop<f_str, const char *>
,prop<f_int, int>
// ,prop<f_float, float> // field is missing in source
>
>
> r1;
r1[f_int::v] = 123;
r1[f_float::v] = 2.7;
r1[f_rec::v][f_str::v] = "Hello World!";
//this structure has fields order changed and one of the fields removed
//but still compatible with the first one for assignment
record
<
prop<f_float, float>,
prop<f_int, int>,
prop
<
f_rec,
record
<
// prop<f_int, int>, // field is missing in target
prop<f_str, const char *>,
prop<f_float, float>
>
>
> r2;
r2 = r1;
r2[f_rec::v][f_str::v] = "Goodbye World!";
cout << "r1: " << typeid(f_int).name() << " == " << r1[f_int::v] << endl;
cout << "r1: " << typeid(f_float).name() << " == " << r1[f_float::v] << endl;
cout << "r1: " << typeid(f_rec).name() << "." << typeid(f_str).name() << " == " << r1[f_rec::v][f_str::v] << endl;
cout << endl;
cout << "r2: " << typeid(f_int).name() << " == " << r2[f_int::v] << endl;
cout << "r2: " << typeid(f_float).name() << " == " << r2[f_float::v] << endl;
cout << "r2: " << typeid(f_rec).name() << "." << typeid(f_str).name() << " == " << r2[f_rec::v][f_str::v] << endl;
cout << endl;
using lln = ll_node<int>;
lln *head = nullptr;
for (auto i = 0; i < 5; ++i)
{
lln *n = new lln;
(*n)[f_next::v] = head;
(*n)[f_data::v] = i;
head = n;
}
for (lln *n = head; n; n = (*n)[f_next::v])
{
cout << (*n)[f_data::v] << endl;
}
return 0;
}
#pragma once
namespace tensors
{
namespace structural
{
template <class T>
struct key_value_traits
{
// key_type;
// value_type;
};
template <typename P>
using key_type_of = typename key_value_traits<P>::key_type;
template <typename P>
using value_type_of = typename key_value_traits<P>::value_type;
}
}
#pragma once
#include "key_value_traits.hpp"
namespace tensors
{
namespace structural
{
template <class K, class V>
struct prop
{
using key_t = K;
using val_t = V;
};
template <class K, class V>
struct key_value_traits<prop<K, V>>
{
using key_type = K;
using value_type = V;
};
}
}
#pragma once
#include <iostream>
#include <typeinfo>
#include <type_traits>
#include "key_value_traits.hpp"
#include "prop.hpp"
namespace tensors
{
namespace type_map
{
namespace details
{
using namespace tensors::structural;
template <typename K, typename K0, typename V0, size_t I, typename P0, typename... P> struct find_prop_type_impl;
template <typename K, size_t I, typename P0, typename... P> struct find_prop_type_impl_unpack;
template <typename K, size_t I, typename...P> using unpack_and_go = find_prop_type_impl_unpack<K, I, P...>;
template <typename K, size_t I, typename P0, typename...P> using forward_to_impl = find_prop_type_impl<K, key_type_of<P0>, value_type_of<P0>, I, P0, P...>;
//has 2+ props: delegate lookup to the unpacker
template <typename K, typename K0, typename V0, size_t I, typename P0, typename... P>
struct find_prop_type_impl
: public unpack_and_go<K, I - 1, P...>
{
using this_type = find_prop_type_impl<K, K0, V0, I, P0, P...>;
using unpack_type = unpack_and_go<K, I - 1, P...>;
using prop_type = typename unpack_type::prop_type;
using unpack_type::is_found;
static std::ostream &print(std::ostream &os)
{
os << "Looking for property with key [" << typeid(K).name() << "] in [" << typeid(this_type).name() << "]..." << std::endl;
return unpack_type::print(os);
}
};
//has 2+ props: already found the match
template <typename K, typename V0, size_t I, typename P0, typename... P>
struct find_prop_type_impl<K, K, V0, I, P0, P...>
{
using this_type = find_prop_type_impl<K, K, V0, I, P0, P...>;
using prop_type = P0;
static constexpr const bool is_found = true;
static std::ostream &print(std::ostream &os)
{
os << "Found the property with key [" << typeid(K).name() << "] in [" << typeid(this_type).name() << "] => [" << typeid(prop_type).name() << "]" << std::endl;
return os;
}
};
enum class unknown_value_type {v};
//has 1 prop: not found
template <typename K, typename K0, typename V0, typename P0>
struct find_prop_type_impl<K, K0, V0, 0, P0>
{
using this_type = find_prop_type_impl<K, K0, V0, 0, P0>;
using prop_type = prop<K, unknown_value_type>;
static constexpr const bool is_found = false;
static std::ostream &print(std::ostream &os)
{
os << "Not found property with key [" << typeid(K).name() << "] in [" << typeid(this_type).name() << "]." << std::endl;
return os;
}
};
//has 1 prop: found the match
template <typename K, typename V0, typename P0>
struct find_prop_type_impl<K, K, V0, 0, P0>
{
using this_type = find_prop_type_impl<K, K, V0, 0, P0>;
using prop_type = P0;
static constexpr const bool is_found = true;
static std::ostream &print(std::ostream &os)
{
os << "Found the property with key [" << typeid(K).name() << "] in [" << typeid(this_type).name() << "] => [" << typeid(prop_type).name() << "]" << std::endl;
return os;
}
};
//has 2+ props: unpack
template <typename K, size_t I, typename P0, typename... P>
struct find_prop_type_impl_unpack
: public forward_to_impl<K, I, P0, P...>
{
using impl_type = forward_to_impl<K, I, P0, P...>;
using prop_type = typename impl_type::prop_type;
using impl_type::is_found;
static std::ostream &print(std::ostream &os) { return impl_type::print(os); }
};
//has 1 prop only: unpack
template <typename K, typename P0>
struct find_prop_type_impl_unpack<K, 0, P0>
: public forward_to_impl<K, 0, P0>
{
using impl_type = forward_to_impl<K, 0, P0>;
using prop_type = typename impl_type::prop_type;
using impl_type::is_found;
static std::ostream &print(std::ostream &os) { return impl_type::print(os); }
};
}
//--------------------------------------------------
template <typename K, typename P0, typename... P>
struct find_prop_type
: public details::unpack_and_go<K, sizeof...(P), P0, P...>
{
using impl = details::unpack_and_go<K, sizeof...(P), P0, P...>;
static std::ostream &print(std::ostream &os) { return impl::print(os); }
};
}
}
#pragma once
#include <iostream>
#include <type_traits>
#include "remove_cvr.hpp"
#include "find_prop_type.hpp"
namespace tensors
{
namespace structural
{
template <typename... P>
class record;
namespace details
{
using namespace std;
using namespace tensors::type_map;
template <typename P>
class record_field_storage
{
using this_type = record_field_storage<P>;
using key_type = key_type_of<P>;
using value_type = value_type_of<P>;
public:
value_type v;
record_field_storage(const std::remove_cvr_t<value_type> &vv) : v(vv) {}
record_field_storage(const this_type &s) = default;
record_field_storage(this_type &&) = default;
record_field_storage() = default;
this_type &operator=(const this_type &s) = default;
};
template <typename K, typename R>
struct check_field
{
static constexpr const bool is_found = false;
};
template <typename K, typename...P>
struct check_field<K, record<P...>>
{
static constexpr const bool is_found = find_prop_type<K, P...>::is_found;
};
template <bool cond, typename K, typename Dst, typename Src>
struct copy_field_impl
{
static void apply(Dst &dst, const Src &src, const K &k) {}
};
template <typename K, typename Dst, typename Src>
struct copy_field_impl<true, K, Dst, Src>
{
static void apply(Dst &dst, const Src &src, const K &k) { dst[k] = src[k]; }
};
template <typename Target, typename Source, size_t I, typename P0, typename...P>
struct record_copier_impl : virtual public record_copier_impl<Target, Source, I - 1, P...>
{
using next = record_copier_impl<Target, Source, I - 1, P...>;
using key_type = key_type_of<P0>;
static const key_type &fake_key() { return *(key_type *)nullptr; }
static void copy(Target &target, const Source &source)
{
constexpr const bool exists_in_both = check_field<key_type, Target>::is_found && check_field<key_type, Source>::is_found;
copy_field_impl<exists_in_both, key_type, Target, Source>::apply(target, source, fake_key());
next::copy(target, source);
}
};
template <typename Target, typename Source, typename P0>
struct record_copier_impl<Target, Source, 0, P0>
{
using key_type = key_type_of<P0>;
static const key_type &fake_key() { return *(key_type *)nullptr; }
static void copy(Target &target, const Source &source)
{
constexpr const bool exists_in_both = check_field<key_type, Target>::is_found && check_field<key_type, Source>::is_found;
copy_field_impl<exists_in_both, key_type, Target, Source>::apply(target, source, fake_key());
}
};
}
template <typename... P>
class record
: virtual details::record_field_storage<P>...
{
using this_type = record<P...>;
template <typename K>
friend struct record_accessor;
template <typename K>
struct record_accessor
{
using record_type = this_type;
using prop_type = typename tensors::type_map::find_prop_type<K, P...>::prop_type;
using key_type = key_type_of<prop_type>;
using value_type = value_type_of<prop_type>;
using storage_type = details::record_field_storage<prop_type>;
static storage_type &property_ref(record_type &r)
{
return static_cast<storage_type &>(r);
}
static const storage_type &property_ref(const record_type &r)
{
return static_cast<const storage_type &>(r);
}
};
template <typename...PS>
struct record_copier : details::record_copier_impl<record<P...>, record<PS...>, sizeof...(P) - 1, P...>
{
using Target = record<P...>;
using Source = record<PS...>;
using impl = details::record_copier_impl<record<P...>, record<PS...>, sizeof...(P) - 1, P...>;
static void copy(Target &target, const Source &source)
{
impl::copy(target, source);
}
};
public:
record() = default;
record(const this_type &) = default;
record(this_type &&) = default;
template <typename K>
typename record_accessor<K>::storage_type &property_ref(const K &)
{
return record_accessor<K>::property_ref(*this);
}
template <typename K>
const typename record_accessor<K>::storage_type &property_ref(const K &) const
{
return record_accessor<K>::property_ref(*this);
}
template <typename K>
typename record_accessor<K>::value_type &operator[](const K &k)
{
return property_ref(k).v;
}
template <typename K>
const typename record_accessor<K>::value_type &operator[](const K &k) const
{
return property_ref(k).v;
}
this_type &operator=(const this_type &s) = default;
template <typename...PS>
this_type &operator=(const record<PS...> &s)
{
record_copier<PS...>::copy(*this, s);
return *this;
}
};
}
}
#pragma once
#include <type_traits>
namespace std
{
template <typename T>
using remove_cvr = remove_cv<typename remove_reference<T>::type>;
template <typename T>
using remove_cvr_t = typename remove_cvr<T>::type;
}