1// This file is part of the ustl library, an STL implementation.
2//
3// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
4// This file is free software, distributed under the MIT License.
5//
6// utuple.h
7//
8
9#ifndef UTUPLE_H_7324ADEC49B397CA74A56F6050FD5A6B
10#define UTUPLE_H_7324ADEC49B397CA74A56F6050FD5A6B
11
12#include "ualgo.h"
13
14#if PLATFORM_ANDROID
15#undef CPU_HAS_MMX
16#endif
17
18namespace ustl {
19
20/// \class tuple utuple.h ustl.h
21/// \ingroup Sequences
22///
23/// \brief A fixed-size array of \p N \p Ts.
24///
25template <size_t N, typename T>
26class tuple {
27public:
28    typedef T						value_type;
29    typedef size_t					size_type;
30    typedef value_type*					pointer;
31    typedef const value_type*				const_pointer;
32    typedef value_type&					reference;
33    typedef const value_type&				const_reference;
34    typedef pointer					iterator;
35    typedef const_pointer				const_iterator;
36    typedef ::ustl::reverse_iterator<iterator>		reverse_iterator;
37    typedef ::ustl::reverse_iterator<const_iterator>	const_reverse_iterator;
38    typedef pair<iterator,iterator>			range_t;
39    typedef pair<const_iterator,const_iterator>		const_range_t;
40public:
41    template <typename T2>
42    inline			tuple (const tuple<N,T2>& t);
43    inline			tuple (const tuple<N,T>& t);
44    inline			tuple (const_pointer v);
45    inline			tuple (void)			{ for (uoff_t i = 0; i < N; ++ i) m_v[i] = T(); }
46    explicit inline		tuple (const_reference v0, const_reference v1 = T(), const_reference v2 = T(), const_reference v3 = T());
47    inline iterator		begin (void)			{ return (m_v); }
48    inline const_iterator	begin (void) const		{ return (m_v); }
49    inline iterator		end (void)			{ return (begin() + N); }
50    inline const_iterator	end (void) const		{ return (begin() + N); }
51    inline size_type		size (void) const		{ return (N); }
52    inline size_type		max_size (void) const		{ return (N); }
53    inline bool			empty (void) const		{ return (N == 0); }
54    inline const_reference	at (size_type i) const		{ return (m_v[i]); }
55    inline reference		at (size_type i)		{ return (m_v[i]); }
56    inline const_reference	operator[] (size_type i) const	{ return (m_v[i]); }
57    inline reference		operator[] (size_type i)	{ return (m_v[i]); }
58    template <typename T2>
59    inline const tuple&		operator= (const tuple<N,T2>& src);
60    inline const tuple&		operator= (const tuple<N,T>& src);
61    inline const tuple&		operator+= (const_reference v)
62				    { for (uoff_t i = 0; i < N; ++ i) m_v[i] += v; return (*this); }
63    inline const tuple&		operator-= (const_reference v)
64				    { for (uoff_t i = 0; i < N; ++ i) m_v[i] -= v; return (*this); }
65    inline const tuple&		operator*= (const_reference v)
66				    { for (uoff_t i = 0; i < N; ++ i) m_v[i] *= v; return (*this); }
67    inline const tuple&		operator/= (const_reference v)
68				    { for (uoff_t i = 0; i < N; ++ i) m_v[i] /= v; return (*this); }
69    inline const tuple		operator+ (const_reference v) const
70				    { tuple result; for (uoff_t i = 0; i < N; ++ i) result[i] = m_v[i] + v; return (result); }
71    inline const tuple		operator- (const_reference v) const
72				    { tuple result; for (uoff_t i = 0; i < N; ++ i) result[i] = m_v[i] - v; return (result); }
73    inline const tuple		operator* (const_reference v) const
74				    { tuple result; for (uoff_t i = 0; i < N; ++ i) result[i] = m_v[i] * v; return (result); }
75    inline const tuple		operator/ (const_reference v) const
76				    { tuple result; for (uoff_t i = 0; i < N; ++ i) result[i] = m_v[i] / v; return (result); }
77    inline void			swap (tuple<N,T>& v)
78				    { for (uoff_t i = 0; i < N; ++ i) ::ustl::swap (m_v[i], v.m_v[i]); }
79private:
80    T				m_v [N];
81};
82
83} // namespace ustl
84
85#include "simd.h"
86
87namespace ustl {
88
89template <size_t N, typename T>
90template <typename T2>
91inline tuple<N,T>::tuple (const tuple<N,T2>& t)
92{ simd::pconvert (t, *this, simd::fcast<T2,T>()); }
93
94template <size_t N, typename T>
95inline tuple<N,T>::tuple (const tuple<N,T>& t)
96{ simd::passign (t, *this); }
97
98template <size_t N, typename T>
99inline tuple<N,T>::tuple (const_pointer v)
100{ simd::ipassign (v, *this); }
101
102template <size_t N, typename T>
103inline tuple<N,T>::tuple (const_reference v0, const_reference v1, const_reference v2, const_reference v3)
104{
105    m_v[0] = v0;
106    if (N > 1) m_v[1] = v1;
107    if (N > 2) m_v[2] = v2;
108    if (N > 3) m_v[3] = v3;
109    if (N > 4) fill_n (m_v + 4, N - 4, T());
110}
111
112template <size_t N, typename T>
113template <typename T2>
114inline const tuple<N,T>& tuple<N,T>::operator= (const tuple<N,T2>& src)
115{ simd::pconvert (src, *this, simd::fcast<T2,T>()); return (*this); }
116
117template <size_t N, typename T>
118inline const tuple<N,T>& tuple<N,T>::operator= (const tuple<N,T>& src)
119{ simd::passign (src, *this); return (*this); }
120
121template <size_t N, typename T1, typename T2>
122inline bool operator== (const tuple<N,T1>& t1, const tuple<N,T2>& t2)
123{
124    for (uoff_t i = 0; i < N; ++ i)
125	if (t1[i] != t2[i])
126	    return (false);
127    return (true);
128}
129
130template <size_t N, typename T1, typename T2>
131inline bool operator< (const tuple<N,T1>& t1, const tuple<N,T2>& t2)
132{
133    for (uoff_t i = 0; i < N && t1[i] <= t2[i]; ++ i)
134	if (t1[i] < t2[i])
135	    return (true);
136    return (false);
137}
138
139template <size_t N, typename T1, typename T2>
140inline const tuple<N,T1>& operator+= (tuple<N,T1>& t1, const tuple<N,T2>& t2)
141    { for (uoff_t i = 0; i < N; ++ i) t1[i] = T1(t1[i] + t2[i]); return (t1); }
142
143template <size_t N, typename T1, typename T2>
144inline const tuple<N,T1>& operator-= (tuple<N,T1>& t1, const tuple<N,T2>& t2)
145    { for (uoff_t i = 0; i < N; ++ i) t1[i] = T1(t1[i] - t2[i]); return (t1); }
146
147template <size_t N, typename T1, typename T2>
148inline const tuple<N,T1>& operator*= (tuple<N,T1>& t1, const tuple<N,T2>& t2)
149    { for (uoff_t i = 0; i < N; ++ i) t1[i] = T1(t1[i] * t2[i]); return (t1); }
150
151template <size_t N, typename T1, typename T2>
152inline const tuple<N,T1>& operator/= (tuple<N,T1>& t1, const tuple<N,T2>& t2)
153    { for (uoff_t i = 0; i < N; ++ i) t1[i] = T1(t1[i] / t2[i]); return (t1); }
154
155template <size_t N, typename T1, typename T2>
156inline const tuple<N,T1> operator+ (const tuple<N,T1>& t1, const tuple<N,T2>& t2)
157{
158    tuple<N,T1> result;
159    for (uoff_t i = 0; i < N; ++ i) result[i] = T1(t1[i] + t2[i]);
160    return (result);
161}
162
163template <size_t N, typename T1, typename T2>
164inline const tuple<N,T1> operator- (const tuple<N,T1>& t1, const tuple<N,T2>& t2)
165{
166    tuple<N,T1> result;
167    for (uoff_t i = 0; i < N; ++ i) result[i] = T1(t1[i] - t2[i]);
168    return (result);
169}
170
171template <size_t N, typename T1, typename T2>
172inline const tuple<N,T1> operator* (const tuple<N,T1>& t1, const tuple<N,T2>& t2)
173{
174    tuple<N,T1> result;
175    for (uoff_t i = 0; i < N; ++ i) result[i] = T1(t1[i] * t2[i]);
176    return (result);
177}
178
179template <size_t N, typename T1, typename T2>
180inline const tuple<N,T1> operator/ (const tuple<N,T1>& t1, const tuple<N,T2>& t2)
181{
182    tuple<N,T1> result;
183    for (uoff_t i = 0; i < N; ++ i) result[i] = T1(t1[i] / t2[i]);
184    return (result);
185}
186
187#if CPU_HAS_SSE
188#define SSE_TUPLE_SPECS(n,type)		\
189template <> inline tuple<n,type>::tuple (void)	\
190{ asm ("xorps %%xmm0, %%xmm0\n\tmovups %%xmm0, %0"::"m"(m_v[0]):"xmm0","memory"); }	\
191template<> inline void tuple<n,type>::swap (tuple<n,type>& v)	\
192{ asm ("movups %0,%%xmm0\n\tmovups %1,%%xmm1\n\tmovups %%xmm0,%1\n\tmovups %%xmm1,%0"::"m"(m_v[0]),"m"(v.m_v[0]):"xmm0","xmm1","memory"); }
193SSE_TUPLE_SPECS(4,float)
194SSE_TUPLE_SPECS(4,int32_t)
195SSE_TUPLE_SPECS(4,uint32_t)
196#undef SSE_TUPLE_SPECS
197#endif
198#if CPU_HAS_MMX
199#define MMX_TUPLE_SPECS(n,type)		\
200template <> inline tuple<n,type>::tuple (void)	\
201{ asm ("pxor %%mm0, %%mm0\n\tmovq %%mm0, %0"::"m"(m_v[0]):"mm0","memory"); simd::reset_mmx(); }	\
202template<> inline void tuple<n,type>::swap (tuple<n,type>& v)	\
203{ asm ("movq %0,%%mm0\n\tmovq %1,%%mm1\n\tmovq %%mm0,%1\n\tmovq %%mm1,%0"::"m"(m_v[0]),"m"(v.m_v[0]):"mm0","mm1","memory"); simd::reset_mmx(); }
204MMX_TUPLE_SPECS(2,float)
205MMX_TUPLE_SPECS(4,int16_t)
206MMX_TUPLE_SPECS(4,uint16_t)
207MMX_TUPLE_SPECS(2,int32_t)
208MMX_TUPLE_SPECS(2,uint32_t)
209MMX_TUPLE_SPECS(8,int8_t)
210MMX_TUPLE_SPECS(8,uint8_t)
211#undef MMX_TUPLE_SPECS
212#endif
213
214#define SIMD_TUPLE_PACKOP(N,T)	\
215template <> inline const tuple<N,T>& operator+= (tuple<N,T>& t1, const tuple<N,T>& t2)	\
216    { simd::padd (t2, t1); return (t1); }						\
217template <> inline const tuple<N,T>& operator-= (tuple<N,T>& t1, const tuple<N,T>& t2)	\
218    { simd::psub (t2, t1); return (t1); }						\
219template <> inline const tuple<N,T>& operator*= (tuple<N,T>& t1, const tuple<N,T>& t2)	\
220    { simd::pmul (t2, t1); return (t1); }						\
221template <> inline const tuple<N,T>& operator/= (tuple<N,T>& t1, const tuple<N,T>& t2)	\
222    { simd::pdiv (t2, t1); return (t1); }						\
223template <> inline const tuple<N,T> operator+ (const tuple<N,T>& t1, const tuple<N,T>& t2) \
224    { tuple<N,T> result (t1); simd::padd (t2, result); return (result); }		\
225template <> inline const tuple<N,T> operator- (const tuple<N,T>& t1, const tuple<N,T>& t2) \
226    { tuple<N,T> result (t1); simd::psub (t2, result); return (result); }		\
227template <> inline const tuple<N,T> operator* (const tuple<N,T>& t1, const tuple<N,T>& t2) \
228    { tuple<N,T> result (t1); simd::pmul (t2, result); return (result); }		\
229template <> inline const tuple<N,T> operator/ (const tuple<N,T>& t1, const tuple<N,T>& t2) \
230    { tuple<N,T> result (t1); simd::pdiv (t2, result); return (result); }
231SIMD_TUPLE_PACKOP(4,float)
232SIMD_TUPLE_PACKOP(2,float)
233SIMD_TUPLE_PACKOP(2,double)
234SIMD_TUPLE_PACKOP(4,int32_t)
235SIMD_TUPLE_PACKOP(4,uint32_t)
236SIMD_TUPLE_PACKOP(4,int16_t)
237SIMD_TUPLE_PACKOP(4,uint16_t)
238SIMD_TUPLE_PACKOP(2,int32_t)
239SIMD_TUPLE_PACKOP(2,uint32_t)
240SIMD_TUPLE_PACKOP(8,int8_t)
241SIMD_TUPLE_PACKOP(8,uint8_t)
242#undef SIMD_TUPLE_PACKOP
243
244} // namespace ustl
245
246#endif
247
248