blob: 1eaa6e66e4cb7f6dbba839c74e3e242dc8bfaea3 [file] [log] [blame]
Mathias Agopian595ea772013-08-21 23:10:41 -07001/*
2 * Copyright 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mathias Agopian595ea772013-08-21 23:10:41 -070017
Romain Guy5d4bae72016-11-08 09:49:25 -080018#ifndef UI_TVECHELPERS_H_
19#define UI_TVECHELPERS_H_
Mathias Agopian595ea772013-08-21 23:10:41 -070020
Romain Guy5d4bae72016-11-08 09:49:25 -080021#include <math.h>
Mathias Agopian595ea772013-08-21 23:10:41 -070022#include <stdint.h>
23#include <sys/types.h>
24
Romain Guy5d4bae72016-11-08 09:49:25 -080025#include <cmath>
26#include <limits>
27#include <iostream>
28
Mathias Agopian595ea772013-08-21 23:10:41 -070029#define PURE __attribute__((pure))
30
31namespace android {
Romain Guy5d4bae72016-11-08 09:49:25 -080032namespace details {
Mathias Agopian595ea772013-08-21 23:10:41 -070033// -------------------------------------------------------------------------------------
34
35/*
36 * No user serviceable parts here.
37 *
38 * Don't use this file directly, instead include ui/vec{2|3|4}.h
39 */
40
41/*
Mathias Agopian1d4d8f92013-09-01 21:35:36 -070042 * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments
Mathias Agopian595ea772013-08-21 23:10:41 -070043 * operators on a vector of type BASE<T>.
44 *
45 * BASE only needs to implement operator[] and size().
Mathias Agopian1d4d8f92013-09-01 21:35:36 -070046 * By simply inheriting from TVec{Add|Product}Operators<BASE, T> BASE will automatically
Mathias Agopian595ea772013-08-21 23:10:41 -070047 * get all the functionality here.
48 */
49
Romain Guy5d4bae72016-11-08 09:49:25 -080050template <template<typename T> class VECTOR, typename T>
Mathias Agopian1d4d8f92013-09-01 21:35:36 -070051class TVecAddOperators {
Mathias Agopian595ea772013-08-21 23:10:41 -070052public:
53 /* compound assignment from a another vector of the same size but different
54 * element type.
55 */
Romain Guy5d4bae72016-11-08 09:49:25 -080056 template<typename OTHER>
57 VECTOR<T>& operator +=(const VECTOR<OTHER>& v) {
58 VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
59 for (size_t i = 0; i < lhs.size(); i++) {
60 lhs[i] += v[i];
Mathias Agopian595ea772013-08-21 23:10:41 -070061 }
Romain Guy5d4bae72016-11-08 09:49:25 -080062 return lhs;
Mathias Agopian595ea772013-08-21 23:10:41 -070063 }
Romain Guy5d4bae72016-11-08 09:49:25 -080064 template<typename OTHER>
65 VECTOR<T>& operator -=(const VECTOR<OTHER>& v) {
66 VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
67 for (size_t i = 0; i < lhs.size(); i++) {
68 lhs[i] -= v[i];
Mathias Agopian595ea772013-08-21 23:10:41 -070069 }
Romain Guy5d4bae72016-11-08 09:49:25 -080070 return lhs;
Mathias Agopian595ea772013-08-21 23:10:41 -070071 }
Mathias Agopian595ea772013-08-21 23:10:41 -070072
73 /* compound assignment from a another vector of the same type.
74 * These operators can be used for implicit conversion and handle operations
75 * like "vector *= scalar" by letting the compiler implicitly convert a scalar
76 * to a vector (assuming the BASE<T> allows it).
77 */
Romain Guy5d4bae72016-11-08 09:49:25 -080078 VECTOR<T>& operator +=(const VECTOR<T>& v) {
79 VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
80 for (size_t i = 0; i < lhs.size(); i++) {
81 lhs[i] += v[i];
Mathias Agopian595ea772013-08-21 23:10:41 -070082 }
Romain Guy5d4bae72016-11-08 09:49:25 -080083 return lhs;
Mathias Agopian595ea772013-08-21 23:10:41 -070084 }
Romain Guy5d4bae72016-11-08 09:49:25 -080085 VECTOR<T>& operator -=(const VECTOR<T>& v) {
86 VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
87 for (size_t i = 0; i < lhs.size(); i++) {
88 lhs[i] -= v[i];
Mathias Agopian595ea772013-08-21 23:10:41 -070089 }
Romain Guy5d4bae72016-11-08 09:49:25 -080090 return lhs;
Mathias Agopian595ea772013-08-21 23:10:41 -070091 }
Mathias Agopian1d4d8f92013-09-01 21:35:36 -070092
93 /*
94 * NOTE: the functions below ARE NOT member methods. They are friend functions
95 * with they definition inlined with their declaration. This makes these
96 * template functions available to the compiler when (and only when) this class
97 * is instantiated, at which point they're only templated on the 2nd parameter
98 * (the first one, BASE<T> being known).
99 */
100
Romain Guy5d4bae72016-11-08 09:49:25 -0800101 /* The operators below handle operation between vectors of the same size
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700102 * but of a different element type.
103 */
104 template<typename RT>
Romain Guy5d4bae72016-11-08 09:49:25 -0800105 friend inline constexpr VECTOR<T> PURE operator +(VECTOR<T> lv, const VECTOR<RT>& rv) {
106 // don't pass lv by reference because we need a copy anyways
107 return lv += rv;
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700108 }
109 template<typename RT>
Romain Guy5d4bae72016-11-08 09:49:25 -0800110 friend inline constexpr VECTOR<T> PURE operator -(VECTOR<T> lv, const VECTOR<RT>& rv) {
111 // don't pass lv by reference because we need a copy anyways
112 return lv -= rv;
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700113 }
114
115 /* The operators below (which are not templates once this class is instanced,
116 * i.e.: BASE<T> is known) can be used for implicit conversion on both sides.
Romain Guy5d4bae72016-11-08 09:49:25 -0800117 * These handle operations like "vector + scalar" and "scalar + vector" by
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700118 * letting the compiler implicitly convert a scalar to a vector (assuming
119 * the BASE<T> allows it).
120 */
Romain Guy5d4bae72016-11-08 09:49:25 -0800121 friend inline constexpr VECTOR<T> PURE operator +(VECTOR<T> lv, const VECTOR<T>& rv) {
122 // don't pass lv by reference because we need a copy anyways
123 return lv += rv;
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700124 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800125 friend inline constexpr VECTOR<T> PURE operator -(VECTOR<T> lv, const VECTOR<T>& rv) {
126 // don't pass lv by reference because we need a copy anyways
127 return lv -= rv;
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700128 }
129};
130
Romain Guy5d4bae72016-11-08 09:49:25 -0800131template<template<typename T> class VECTOR, typename T>
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700132class TVecProductOperators {
133public:
134 /* compound assignment from a another vector of the same size but different
135 * element type.
136 */
Romain Guy5d4bae72016-11-08 09:49:25 -0800137 template<typename OTHER>
138 VECTOR<T>& operator *=(const VECTOR<OTHER>& v) {
139 VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
140 for (size_t i = 0; i < lhs.size(); i++) {
141 lhs[i] *= v[i];
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700142 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800143 return lhs;
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700144 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800145 template<typename OTHER>
146 VECTOR<T>& operator /=(const VECTOR<OTHER>& v) {
147 VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
148 for (size_t i = 0; i < lhs.size(); i++) {
149 lhs[i] /= v[i];
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700150 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800151 return lhs;
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700152 }
153
154 /* compound assignment from a another vector of the same type.
155 * These operators can be used for implicit conversion and handle operations
156 * like "vector *= scalar" by letting the compiler implicitly convert a scalar
157 * to a vector (assuming the BASE<T> allows it).
158 */
Romain Guy5d4bae72016-11-08 09:49:25 -0800159 VECTOR<T>& operator *=(const VECTOR<T>& v) {
160 VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
161 for (size_t i = 0; i < lhs.size(); i++) {
162 lhs[i] *= v[i];
Mathias Agopian595ea772013-08-21 23:10:41 -0700163 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800164 return lhs;
Mathias Agopian595ea772013-08-21 23:10:41 -0700165 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800166 VECTOR<T>& operator /=(const VECTOR<T>& v) {
167 VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
168 for (size_t i = 0; i < lhs.size(); i++) {
169 lhs[i] /= v[i];
Mathias Agopian595ea772013-08-21 23:10:41 -0700170 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800171 return lhs;
Mathias Agopian595ea772013-08-21 23:10:41 -0700172 }
173
174 /*
175 * NOTE: the functions below ARE NOT member methods. They are friend functions
176 * with they definition inlined with their declaration. This makes these
177 * template functions available to the compiler when (and only when) this class
178 * is instantiated, at which point they're only templated on the 2nd parameter
179 * (the first one, BASE<T> being known).
180 */
181
Romain Guy5d4bae72016-11-08 09:49:25 -0800182 /* The operators below handle operation between vectors of the same size
Mathias Agopian595ea772013-08-21 23:10:41 -0700183 * but of a different element type.
184 */
185 template<typename RT>
Romain Guy5d4bae72016-11-08 09:49:25 -0800186 friend inline constexpr VECTOR<T> PURE operator *(VECTOR<T> lv, const VECTOR<RT>& rv) {
187 // don't pass lv by reference because we need a copy anyways
188 return lv *= rv;
Mathias Agopian595ea772013-08-21 23:10:41 -0700189 }
190 template<typename RT>
Romain Guy5d4bae72016-11-08 09:49:25 -0800191 friend inline constexpr VECTOR<T> PURE operator /(VECTOR<T> lv, const VECTOR<RT>& rv) {
192 // don't pass lv by reference because we need a copy anyways
193 return lv /= rv;
Mathias Agopian595ea772013-08-21 23:10:41 -0700194 }
195
196 /* The operators below (which are not templates once this class is instanced,
197 * i.e.: BASE<T> is known) can be used for implicit conversion on both sides.
198 * These handle operations like "vector * scalar" and "scalar * vector" by
199 * letting the compiler implicitly convert a scalar to a vector (assuming
200 * the BASE<T> allows it).
201 */
Romain Guy5d4bae72016-11-08 09:49:25 -0800202 friend inline constexpr VECTOR<T> PURE operator *(VECTOR<T> lv, const VECTOR<T>& rv) {
203 // don't pass lv by reference because we need a copy anyways
204 return lv *= rv;
Mathias Agopian595ea772013-08-21 23:10:41 -0700205 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800206 friend inline constexpr VECTOR<T> PURE operator /(VECTOR<T> lv, const VECTOR<T>& rv) {
207 // don't pass lv by reference because we need a copy anyways
208 return lv /= rv;
Mathias Agopian595ea772013-08-21 23:10:41 -0700209 }
210};
211
212/*
213 * TVecUnaryOperators implements unary operators on a vector of type BASE<T>.
214 *
215 * BASE only needs to implement operator[] and size().
216 * By simply inheriting from TVecUnaryOperators<BASE, T> BASE will automatically
217 * get all the functionality here.
218 *
219 * These operators are implemented as friend functions of TVecUnaryOperators<BASE, T>
220 */
Romain Guy5d4bae72016-11-08 09:49:25 -0800221template<template<typename T> class VECTOR, typename T>
Mathias Agopian595ea772013-08-21 23:10:41 -0700222class TVecUnaryOperators {
223public:
Romain Guy5d4bae72016-11-08 09:49:25 -0800224 VECTOR<T>& operator ++() {
225 VECTOR<T>& rhs = static_cast<VECTOR<T>&>(*this);
226 for (size_t i = 0; i < rhs.size(); i++) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700227 ++rhs[i];
228 }
229 return rhs;
230 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800231 VECTOR<T>& operator --() {
232 VECTOR<T>& rhs = static_cast<VECTOR<T>&>(*this);
233 for (size_t i = 0; i < rhs.size(); i++) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700234 --rhs[i];
235 }
236 return rhs;
237 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800238 VECTOR<T> operator -() const {
239 VECTOR<T> r(VECTOR<T>::NO_INIT);
240 VECTOR<T> const& rv(static_cast<VECTOR<T> const&>(*this));
241 for (size_t i = 0; i < r.size(); i++) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700242 r[i] = -rv[i];
243 }
244 return r;
245 }
246};
247
Mathias Agopian595ea772013-08-21 23:10:41 -0700248/*
249 * TVecComparisonOperators implements relational/comparison operators
250 * on a vector of type BASE<T>.
251 *
252 * BASE only needs to implement operator[] and size().
253 * By simply inheriting from TVecComparisonOperators<BASE, T> BASE will automatically
254 * get all the functionality here.
255 */
Romain Guy5d4bae72016-11-08 09:49:25 -0800256template<template<typename T> class VECTOR, typename T>
Mathias Agopian595ea772013-08-21 23:10:41 -0700257class TVecComparisonOperators {
258public:
259 /*
260 * NOTE: the functions below ARE NOT member methods. They are friend functions
261 * with they definition inlined with their declaration. This makes these
262 * template functions available to the compiler when (and only when) this class
263 * is instantiated, at which point they're only templated on the 2nd parameter
264 * (the first one, BASE<T> being known).
265 */
266 template<typename RT>
267 friend inline
Romain Guy5d4bae72016-11-08 09:49:25 -0800268 bool PURE operator ==(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
269 for (size_t i = 0; i < lv.size(); i++)
Mathias Agopian595ea772013-08-21 23:10:41 -0700270 if (lv[i] != rv[i])
271 return false;
272 return true;
273 }
274
275 template<typename RT>
276 friend inline
Romain Guy5d4bae72016-11-08 09:49:25 -0800277 bool PURE operator !=(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700278 return !operator ==(lv, rv);
279 }
280
281 template<typename RT>
282 friend inline
Romain Guy5d4bae72016-11-08 09:49:25 -0800283 bool PURE operator >(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
284 for (size_t i = 0; i < lv.size(); i++) {
285 if (lv[i] == rv[i]) {
286 continue;
287 }
288 return lv[i] > rv[i];
289 }
290 return false;
Mathias Agopian595ea772013-08-21 23:10:41 -0700291 }
292
293 template<typename RT>
294 friend inline
Romain Guy5d4bae72016-11-08 09:49:25 -0800295 constexpr bool PURE operator <=(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700296 return !(lv > rv);
297 }
298
299 template<typename RT>
300 friend inline
Romain Guy5d4bae72016-11-08 09:49:25 -0800301 bool PURE operator <(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
302 for (size_t i = 0; i < lv.size(); i++) {
303 if (lv[i] == rv[i]) {
304 continue;
305 }
306 return lv[i] < rv[i];
307 }
308 return false;
Mathias Agopian595ea772013-08-21 23:10:41 -0700309 }
310
311 template<typename RT>
312 friend inline
Romain Guy5d4bae72016-11-08 09:49:25 -0800313 constexpr bool PURE operator >=(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700314 return !(lv < rv);
315 }
316};
317
Mathias Agopian595ea772013-08-21 23:10:41 -0700318/*
319 * TVecFunctions implements functions on a vector of type BASE<T>.
320 *
321 * BASE only needs to implement operator[] and size().
322 * By simply inheriting from TVecFunctions<BASE, T> BASE will automatically
323 * get all the functionality here.
324 */
Romain Guy5d4bae72016-11-08 09:49:25 -0800325template<template<typename T> class VECTOR, typename T>
Mathias Agopian595ea772013-08-21 23:10:41 -0700326class TVecFunctions {
327public:
328 /*
329 * NOTE: the functions below ARE NOT member methods. They are friend functions
330 * with they definition inlined with their declaration. This makes these
331 * template functions available to the compiler when (and only when) this class
332 * is instantiated, at which point they're only templated on the 2nd parameter
333 * (the first one, BASE<T> being known).
334 */
335 template<typename RT>
Romain Guy5d4bae72016-11-08 09:49:25 -0800336 friend inline T PURE dot(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700337 T r(0);
Romain Guy5d4bae72016-11-08 09:49:25 -0800338 for (size_t i = 0; i < lv.size(); i++) {
339 //r = std::fma(lv[i], rv[i], r);
340 r += lv[i] * rv[i];
341 }
Mathias Agopian595ea772013-08-21 23:10:41 -0700342 return r;
343 }
344
Romain Guy5d4bae72016-11-08 09:49:25 -0800345 friend inline constexpr T PURE norm(const VECTOR<T>& lv) {
346 return std::sqrt(dot(lv, lv));
347 }
348
349 friend inline constexpr T PURE length(const VECTOR<T>& lv) {
350 return norm(lv);
351 }
352
353 friend inline constexpr T PURE norm2(const VECTOR<T>& lv) {
354 return dot(lv, lv);
355 }
356
357 friend inline constexpr T PURE length2(const VECTOR<T>& lv) {
358 return norm2(lv);
Mathias Agopian595ea772013-08-21 23:10:41 -0700359 }
360
361 template<typename RT>
Romain Guy5d4bae72016-11-08 09:49:25 -0800362 friend inline constexpr T PURE distance(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700363 return length(rv - lv);
364 }
365
Romain Guy5d4bae72016-11-08 09:49:25 -0800366 template<typename RT>
367 friend inline constexpr T PURE distance2(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
368 return length2(rv - lv);
369 }
370
371 friend inline constexpr VECTOR<T> PURE normalize(const VECTOR<T>& lv) {
372 return lv * (T(1) / length(lv));
373 }
374
375 friend inline VECTOR<T> PURE rcp(VECTOR<T> v) {
376 return T(1) / v;
377 }
378
379 friend inline VECTOR<T> PURE abs(VECTOR<T> v) {
380 for (size_t i=0 ; i<v.size() ; i++) {
381 v[i] = std::abs(v[i]);
382 }
383 return v;
384 }
385
386 friend inline VECTOR<T> PURE floor(VECTOR<T> v) {
387 for (size_t i=0 ; i<v.size() ; i++) {
388 v[i] = std::floor(v[i]);
389 }
390 return v;
391 }
392
393 friend inline VECTOR<T> PURE ceil(VECTOR<T> v) {
394 for (size_t i=0 ; i<v.size() ; i++) {
395 v[i] = std::ceil(v[i]);
396 }
397 return v;
398 }
399
400 friend inline VECTOR<T> PURE round(VECTOR<T> v) {
401 for (size_t i=0 ; i<v.size() ; i++) {
402 v[i] = std::round(v[i]);
403 }
404 return v;
405 }
406
407 friend inline VECTOR<T> PURE inversesqrt(VECTOR<T> v) {
408 for (size_t i=0 ; i<v.size() ; i++) {
409 v[i] = T(1) / std::sqrt(v[i]);
410 }
411 return v;
412 }
413
414 friend inline VECTOR<T> PURE sqrt(VECTOR<T> v) {
415 for (size_t i=0 ; i<v.size() ; i++) {
416 v[i] = std::sqrt(v[i]);
417 }
418 return v;
419 }
420
421 friend inline VECTOR<T> PURE pow(VECTOR<T> v, T p) {
422 for (size_t i=0 ; i<v.size() ; i++) {
423 v[i] = std::pow(v[i], p);
424 }
425 return v;
426 }
427
428 friend inline VECTOR<T> PURE saturate(const VECTOR<T>& lv) {
429 return clamp(lv, T(0), T(1));
430 }
431
432 friend inline VECTOR<T> PURE clamp(VECTOR<T> v, T min, T max) {
433 for (size_t i=0 ; i< v.size() ; i++) {
434 v[i] = std::min(max, std::max(min, v[i]));
435 }
436 return v;
437 }
438
439 friend inline VECTOR<T> PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv, VECTOR<T> a) {
440 for (size_t i=0 ; i<lv.size() ; i++) {
441 //a[i] = std::fma(lv[i], rv[i], a[i]);
442 a[i] += (lv[i] * rv[i]);
443 }
444 return a;
445 }
446
447 friend inline VECTOR<T> PURE min(const VECTOR<T>& u, VECTOR<T> v) {
448 for (size_t i=0 ; i<v.size() ; i++) {
449 v[i] = std::min(u[i], v[i]);
450 }
451 return v;
452 }
453
454 friend inline VECTOR<T> PURE max(const VECTOR<T>& u, VECTOR<T> v) {
455 for (size_t i=0 ; i<v.size() ; i++) {
456 v[i] = std::max(u[i], v[i]);
457 }
458 return v;
459 }
460
461 friend inline T PURE max(const VECTOR<T>& v) {
462 T r(std::numeric_limits<T>::lowest());
463 for (size_t i=0 ; i<v.size() ; i++) {
464 r = std::max(r, v[i]);
465 }
466 return r;
467 }
468
469 friend inline T PURE min(const VECTOR<T>& v) {
470 T r(std::numeric_limits<T>::max());
471 for (size_t i=0 ; i<v.size() ; i++) {
472 r = std::min(r, v[i]);
473 }
474 return r;
475 }
476};
477
478/*
479 * TVecDebug implements functions on a vector of type BASE<T>.
480 *
481 * BASE only needs to implement operator[] and size().
482 * By simply inheriting from TVecDebug<BASE, T> BASE will automatically
483 * get all the functionality here.
484 */
485template<template<typename T> class VECTOR, typename T>
486class TVecDebug {
487public:
488 /*
489 * NOTE: the functions below ARE NOT member methods. They are friend functions
490 * with they definition inlined with their declaration. This makes these
491 * template functions available to the compiler when (and only when) this class
492 * is instantiated, at which point they're only templated on the 2nd parameter
493 * (the first one, BASE<T> being known).
494 */
495 friend std::ostream& operator<<(std::ostream& stream, const VECTOR<T>& v) {
496 stream << "< ";
497 for (size_t i = 0; i < v.size() - 1; i++) {
498 stream << T(v[i]) << ", ";
499 }
500 stream << T(v[v.size() - 1]) << " >";
501 return stream;
Mathias Agopian595ea772013-08-21 23:10:41 -0700502 }
503};
504
505#undef PURE
506
507// -------------------------------------------------------------------------------------
Romain Guy5d4bae72016-11-08 09:49:25 -0800508} // namespace details
509} // namespace android
Mathias Agopian595ea772013-08-21 23:10:41 -0700510
511
Romain Guy5d4bae72016-11-08 09:49:25 -0800512#endif // UI_TVECHELPERS_H_