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