Skip to content

Instantly share code, notes, and snippets.

@marionette-of-u
Last active August 29, 2015 13:58
Show Gist options
  • Select an option

  • Save marionette-of-u/9983751 to your computer and use it in GitHub Desktop.

Select an option

Save marionette-of-u/9983751 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
int main(){
using namespace mll;
// variant.
// template arguments で与えられたどれかの型の変数を保持.
{
mll::variant<int, std::string> v;
int a = 10;
std::string str = "Hello.";
v = a;
std::cout << v.info->name() << std::endl;
v = std::move(str);
std::cout << v.info->name() << std::endl;
// composite.
// template arguments で与えられた全ての型の変数を保持.
mll::composite<int, std::string, int*> instance;
instance.get<0>() = 10;
instance.get<1>() = "test";
instance.get<2>() = &instance.get<0>();
std::cout << instance.get<0>() << std::endl;
std::cout << instance.get<1>() << std::endl;
std::cout << instance.get<2>() << std::endl;
std::cout << *instance.get<2>() << std::endl;
}
// recursive variant.
// 再帰構造の variant. 再帰指定子は rec.
// と言いたいところだけど, 実はただの any.
{
using multi_tree = variant<std::string, int, variant<composite<rec, rec>, composite<rec, rec, rec>>>;
multi_tree root;
variant<composite<rec, rec>, composite<rec, rec, rec>> tree;
composite<rec, rec> binary_tree;
// binary tree.
{
std::string str = "first";
int x = 2;
multi_tree a, b, c;
a = str;
b = x;
binary_tree.get<0>() = a;
binary_tree.get<1>() = b;
tree = binary_tree;
root = tree;
}
}
return 0;
}
#include <tuple>
#include <memory>
#include <utility>
#include <forward_list>
#include <type_traits>
#include <typeinfo>
// ML Like.
namespace mll{
template<class Dummy = void>
class base_type{
public:
template<class T>
static void template_deleter(void *ptr){ delete static_cast<T*>(ptr); }
using deleter = void(*)(void*);
template<class T>
static void *template_cctor(void *ptr){ return new T(*static_cast<T*>(ptr)); }
using cctor = void*(*)(void*);
const std::type_info *const &info = ptr_type_info;
private:
void *ptr = nullptr;
deleter del;
cctor ctor;
const std::type_info *ptr_type_info = nullptr;
public:
template<class T>
void set_const(const T &other){
using type = typename std::remove_reference<T>::type;
if(ptr && *info != typeid(type)){
del(ptr);
ptr = nullptr;
}
del = template_deleter<type>;
ptr = new type(other);
ptr_type_info = &typeid(type);
ctor = template_cctor<type>;
}
template<class T>
void set_move(T &&other){
using type = typename std::remove_reference<T>::type;
if(ptr && *info != typeid(type)){
del(ptr);
ptr = nullptr;
}
del = template_deleter<type>;
ptr = new type(other);
ptr_type_info = &typeid(type);
ctor = template_cctor<type>;
}
base_type() = default;
base_type(const base_type<Dummy> &other) :
ptr(other.ctor(other.ptr)),
del(other.del),
ctor(other.ctor),
ptr_type_info(other.ptr_type_info)
{}
virtual ~base_type(){
if(ptr){ del(ptr); }
}
};
class rec_impl : public base_type<>{
public:
template<class T>
rec_impl &operator =(const T &other){
set_const(other);
return *this;
}
template<class T>
rec_impl &operator =(T &&other){
set_move(other);
return *this;
}
~rec_impl() = default;
};
using rec = rec_impl;
template<class T>
class list : public std::forward_list<T>{};
template<class T>
bool operator ==(const list<T> &lhs, const list<T> &rhs){
auto iter = lhs.cbegin(), jter = rhs.cbegin(), end = lhs.cend();
for(; iter != end; ++iter, ++jter){
if(*iter == *jter){ continue; }
return false;
}
return jter == rhs.cend();
}
template<class T>
bool operator !=(const list<T> &lhs, const list<T> &rhs){
return !(lhs == rhs);
}
template<class... Seq>
class composite;
template<class... Seq>
class variant;
// type_tuple.
namespace aux{
// 重複を許可する.
template<class... Seq>
struct type_tuple;
// index-based access.
template<std::size_t Idx, class... Seq>
struct get_type;
template<class Head, class... Rest>
struct get_type<0, Head, Rest...>{
using type = Head;
};
template<std::size_t Idx, class Head, class... Seq>
struct get_type<Idx, Head, Seq...>{
using type = typename get_type<Idx - 1, Seq...>::type;
};
}
// value_tuple.
namespace aux{
// recursive tag to root.
template<class Root, class Other>
struct recursive_tag_to_root{
using type = Other;
};
template<class Root>
struct recursive_tag_to_root<Root, rec>{
using type = Root;
};
}
// composite (= "type").
// 型を合成する.
template<class... Seq>
class composite{
template<class... Seq>
friend bool operator ==(const composite<Seq...> &lhs, const composite<Seq...> &rhs);
private:
using type_tuple = aux::type_tuple<Seq...>;
std::tuple<Seq...> value_tuple;
public:
template<std::size_t N>
using type = typename aux::get_type<N, Seq...>::type;
composite<Seq...> &operator =(const composite<Seq...> &other){
value_tuple = other.value_tuple;
return *this;
}
template<std::size_t Idx>
typename std::tuple_element<Idx, std::tuple<Seq...>>::type &get(){
return std::get<Idx>(value_tuple);
}
template<std::size_t Idx>
const typename std::tuple_element<Idx, std::tuple<Seq...>>::type &get() const{
return std::get<Idx>(value_tuple);
}
composite() = default;
~composite() = default;
};
template<class... Seq>
bool operator ==(const composite<Seq...> &lhs, const composite<Seq...> &rhs){
return lhs.value_tuple == rhs.value_tuple;
}
template<class... Seq>
bool operator !=(const composite<Seq...> &lhs, const composite<Seq...> &rhs){
return !(lhs == rhs);
}
// (... for variant).
namespace aux{
// 重複している型があるかどうか check.
template<class... T>
struct head_holder;
template<class T>
struct head_holder<T>{};
template<>
struct head_holder<>{};
template<class... Seq>
struct rest_holder;
template<>
struct rest_holder<>{};
template<class... Seq>
struct get_head_rest;
template<class Head, class... Seq>
struct get_head_rest<Head, Seq...>{
using head = head_holder<Head>;
using rest = rest_holder<Seq...>;
};
template<class Head>
struct get_head_rest<Head>{
using head = head_holder<Head>;
using rest = rest_holder<>;
};
template<>
struct get_head_rest<>{
using head = head_holder<>;
using rest = rest_holder<>;
};
template<class Holder, class... Seq>
struct check_duplicate;
template<class T, class Head, class... Seq>
struct check_duplicate<head_holder<T>, rest_holder<Head, Seq...>>{
static const bool value =
check_duplicate<head_holder<T>, rest_holder<Seq... >>::value &&
check_duplicate<head_holder<Head>, rest_holder<Seq...>>::value;
};
template<class T, class... Seq>
struct check_duplicate<head_holder<T>, rest_holder<T, Seq...>>{
static const bool value = false;
};
template<class T>
struct check_duplicate<head_holder<T>, rest_holder<>>{
static const bool value = true;
};
// identity for scan template arguments.
template<class Root>
struct root_holder{
using type = Root;
};
// exist.
template<class Root, class T, class Rest>
struct check_exist;
template<class Root, class T>
struct check_exist<Root, head_holder<T>, rest_holder<>>{
static const bool value = false;
};
template<class Root, class T, class U, class... Seq>
struct check_exist<Root, head_holder<T>, rest_holder<U, Seq...>>{
static const bool value = check_exist<Root, head_holder<T>, rest_holder<Seq...>>::value;
};
template<class Root, class T, class... Rest>
struct check_exist<Root, head_holder<T>, rest_holder<T, Rest...>>{
static const bool value = true;
};
template<class T, class... Rest>
struct check_exist<root_holder<T>, head_holder<T>, rest_holder<rec, Rest...>>{
static const bool value = true;
};
template<class Root, class T, class... Rest>
struct check_exist<Root, head_holder<list<T>>, rest_holder<list<T>, Rest...>>{
static const bool value = true;
};
template<class Root, class... Rest>
struct check_exist<Root, head_holder<list<typename Root::type>>, rest_holder<list<rec>, Rest...>>{
static const bool value = true;
};
template<class Root, class T, class U, class... Rest>
struct check_exist<Root, head_holder<list<T>>, rest_holder<list<U>, Rest...>>{
static const bool value =
check_exist<Root, head_holder<T>, rest_holder<U>>::value ||
check_exist<Root, head_holder<list<T>>, rest_holder<Rest...>>::value;
};
}
// variant (= "datatype").
template<class... Seq>
class variant : public base_type<>{
// 重複を許可しない.
static_assert(
aux::check_duplicate<
typename aux::get_head_rest<Seq...>::head,
typename aux::get_head_rest<Seq...>::rest
>::value,
"assert(check_duplicate::value)."
);
private:
using type_tuple = aux::type_tuple<Seq...>;
template<class RHS>
variant<Seq...> &assign_impl(const RHS &x){
set_const(x);
return *this;
}
template<class RHS>
variant<Seq...> &assign_impl(RHS &&x){
set_move(x);
return *this;
}
public:
template<std::size_t N>
using type = typename aux::get_type<N, Seq...>::type;
template<std::size_t Idx>
typename aux::recursive_tag_to_root<variant<Seq...>, type<Idx>>::type &get(){
return *static_cast<typename aux::recursive_tag_to_root<variant<Seq...>, type<Idx>>::type*>(ptr);
}
template<std::size_t Idx>
const typename aux::recursive_tag_to_root<variant<Seq...>, type<Idx>>::type &get() const{
return *static_cast<const typename aux::recursive_tag_to_root<variant<Seq...>, type<Idx>>::type*>(ptr);
}
template<class RHS>
variant<Seq...> &operator =(const RHS &x){
using rhs = typename std::remove_reference<RHS>::type;
return assign_impl<const rhs&>(x);
return *this;
}
template<class RHS>
variant<Seq...> &operator =(RHS &&x){
using rhs = typename std::remove_reference<typename std::remove_reference<RHS>::type>::type;
return assign_impl<rhs&&>(static_cast<rhs&&>(x));
}
variant() = default;
~variant() = default;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment