1 // The MIT License (MIT)
2 
3 // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef SOL_TIE_HPP
23 #define SOL_TIE_HPP
24 
25 #include "traits.hpp"
26 
27 namespace sol {
28 
29 	namespace detail {
30 		template <typename T>
31 		struct is_speshul : std::false_type {};
32 	}
33 
34 	template <typename T>
35 	struct tie_size : std::tuple_size<T> {};
36 
37 	template <typename T>
38 	struct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> {};
39 
40 	template <typename... Tn>
41 	struct tie_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> {
42 	private:
43 		typedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t;
44 
45 		template <typename T>
setsol::tie_t46 		void set(std::false_type, T&& target) {
47 			std::get<0>(*this) = std::forward<T>(target);
48 		}
49 
50 		template <typename T>
setsol::tie_t51 		void set(std::true_type, T&& target) {
52 			typedef tie_size<meta::unqualified_t<T>> value_size;
53 			typedef tie_size<std::tuple<Tn...>> tie_size;
54 			typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size;
55 			typedef std::make_index_sequence<indices_size::value> indices;
56 			set_extra(detail::is_speshul<meta::unqualified_t<T>>(), indices(), std::forward<T>(target));
57 		}
58 
59 		template <std::size_t... I, typename T>
set_extrasol::tie_t60 		void set_extra(std::true_type, std::index_sequence<I...>, T&& target) {
61 			using std::get;
62 			(void)detail::swallow{ 0,
63 				(get<I>(static_cast<base_t&>(*this)) = get<I>(types<Tn...>(), target), 0)...
64 				, 0 };
65 		}
66 
67 		template <std::size_t... I, typename T>
set_extrasol::tie_t68 		void set_extra(std::false_type, std::index_sequence<I...>, T&& target) {
69 			using std::get;
70 			(void)detail::swallow{ 0,
71 				(get<I>(static_cast<base_t&>(*this)) = get<I>(target), 0)...
72 				, 0 };
73 		}
74 
75 	public:
76 		using base_t::base_t;
77 
78 		template <typename T>
operator =sol::tie_t79 		tie_t& operator= (T&& value) {
80 			typedef is_tieable<meta::unqualified_t<T>> tieable;
81 			set(tieable(), std::forward<T>(value));
82 			return *this;
83 		}
84 
85 	};
86 
87 	template <typename... Tn>
88 	struct tie_size< tie_t<Tn...> > : std::tuple_size< std::tuple<Tn...> > { };
89 
90 	namespace adl_barrier_detail {
91 		template <typename... Tn>
tie(Tn &&...argn)92 		inline tie_t<std::remove_reference_t<Tn>...> tie(Tn&&... argn) {
93 			return tie_t<std::remove_reference_t<Tn>...>(std::forward<Tn>(argn)...);
94 		}
95 	}
96 
97 	using namespace adl_barrier_detail;
98 
99 } // sol
100 
101 #endif // SOL_TIE_HPP
102