Last active
August 29, 2015 13:58
-
-
Save marionette-of-u/9983751 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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