Types.h 44.1 KB
Newer Older
1 2 3 4 5 6 7 8
//============================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//
9
//  Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10
//  Copyright 2014 UT-Battelle, LLC.
11
//  Copyright 2014 Los Alamos National Security.
12
//
13
//  Under the terms of Contract DE-NA0003525 with NTESS,
14 15 16 17 18 19
//  the U.S. Government retains certain rights in this software.
//
//  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
//  Laboratory (LANL), the U.S. Government retains certain rights in
//  this software.
//============================================================================
20 21 22
#ifndef vtk_m_Types_h
#define vtk_m_Types_h

23 24 25
#include <vtkm/internal/Configure.h>
#include <vtkm/internal/ExportMacros.h>

26
#include <vtkm/Assert.h>
27
#include <vtkm/StaticAssert.h>
28

29
#include <iostream>
30
#include <type_traits>
31

32 33
/*!
 * \namespace vtkm
34
 * \brief VTK-m Toolkit.
35
 *
36 37
 * vtkm is the namespace for the VTK-m Toolkit. It contains other sub namespaces,
 * as well as basic data types and functions callable from all components in VTK-m
38 39 40
 * toolkit.
 *
 * \namespace vtkm::cont
41
 * \brief VTK-m Control Environment.
42
 *
43 44
 * vtkm::cont defines the publicly accessible API for the VTK-m Control
 * Environment. Users of the VTK-m Toolkit can use this namespace to access the
45 46
 * Control Environment.
 *
47 48 49 50
 * \namespace vtkm::cont::arg
 * \brief Transportation controls for Control Environment Objects.
 *
 * vtkm::cont::arg includes the classes that allows the vtkm::worklet::Dispatchers
luz.paz's avatar
luz.paz committed
51
 * to request Control Environment Objects to be transferred to the Execution Environment.
52
 *
53
 * \namespace vtkm::cont::cuda
54 55
 * \brief CUDA implementation for Control Environment.
 *
56 57 58 59 60 61 62 63 64 65 66 67 68 69
 * vtkm::cont::cuda includes the code to implement the VTK-m Control Environment
 * for the CUDA-based device adapter.
 *
 * \namespace vtkm::cont::serial
 * \brief Serial implementation for Control Environment.
 *
 * vtkm::cont::serial includes the code to implement the VTK-m Control Environment
 * for the serial device adapter.
 *
 * \namespace vtkm::cont::tbb
 * \brief TBB implementation for Control Environment.
 *
 * vtkm::cont::tbb includes the code to implement the VTK-m Control Environment
 * for the TBB-based device adapter.
70 71
 *
 * \namespace vtkm::exec
72
 * \brief VTK-m Execution Environment.
73
 *
74
 * vtkm::exec defines the publicly accessible API for the VTK-m Execution
75 76 77
 * Environment. Worklets typically use classes/apis defined within this
 * namespace alone.
 *
78 79 80
 * \namespace vtkm::exec::cuda
 * \brief CUDA implementation for Execution Environment.
 *
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
 * vtkm::exec::cuda includes the code to implement the VTK-m Execution Environment
 * for the CUDA-based device adapter.
 *
 * \namespace vtkm::exec::serial
 * \brief CUDA implementation for Execution Environment.
 *
 * vtkm::exec::serial includes the code to implement the VTK-m Execution Environment
 * for the serial device adapter.
 *
 * \namespace vtkm::exec::tbb
 * \brief TBB implementation for Execution Environment.
 *
 * vtkm::exec::tbb includes the code to implement the VTK-m Execution Environment
 * for the TBB device adapter.
 *
 * \namespace vtkm::filter
 * \brief VTK-m Filters
 *
 * vtkm::filter is the collection of predefined filters that take data as input
 * and write new data as output. Filters operate on vtkm::cont::DataSet objects,
 * vtkm::cont::Fields, and other runtime typeless objects.
102
 *
103
 * \namespace vtkm::internal
104
 * \brief VTK-m Internal Environment
105 106
 *
 * vtkm::internal defines API which is internal and subject to frequent
107 108
 * change. This should not be used for projects using VTK-m. Instead it servers
 * are a reference for the developers of VTK-m.
109
 *
110
 * \namespace vtkm::interop
111
 * \brief VTK-m OpenGL Interoperability
112
 *
113
 * vtkm::interop defines the publicly accessible API for interoperability between
114 115 116 117 118 119 120 121 122 123 124 125
 * vtkm and OpenGL.
 *
 * \namespace vtkm::io
 * \brief VTK-m IO
 *
 * vtkm::io defines API for basic reading of VTK files. Intended to be used for
 * examples and testing.
 *
 * \namespace vtkm::rendering
 * \brief VTK-m Rendering
 *
 * vtkm::rendering defines API for
126 127 128 129
 *
 * \namespace vtkm::testing
 * \brief Internal testing classes
 *
130 131 132 133 134 135 136 137 138
 * \namespace vtkm::worklet
 * \brief VTK-m Worklets
 *
 * vtkm::worklet defines API for the low level worklets that operate on an element of data,
 * and the dispatcher that execute them in the execution environment.
 *
 * VTK-m provides numerous worklet implementations. These worklet implementations for the most
 * part provide the underlying implementations of the algorithms in vtkm::filter.
 *
139 140
 */

141 142
namespace vtkm
{
143 144 145
//*****************************************************************************
// Typedefs for basic types.
//*****************************************************************************
146 147 148 149 150 151 152 153
using Float32 = float;
using Float64 = double;
using Int8 = signed char;
using UInt8 = unsigned char;
using Int16 = short;
using UInt16 = unsigned short;
using Int32 = int;
using UInt32 = unsigned int;
154 155 156 157 158 159 160

/// Represents a component ID (index of component in a vector). The number
/// of components, being a value fixed at compile time, is generally assumed
/// to be quite small. However, we are currently using a 32-bit width
/// integer because modern processors tend to access them more efficiently
/// than smaller widths.
using IdComponent = vtkm::Int32;
161

162 163
//In this order so that we exactly match the logic that exists in VTK
#if VTKM_SIZE_LONG_LONG == 8
164 165
using Int64 = long long;
using UInt64 = unsigned long long;
166
#elif VTKM_SIZE_LONG == 8
167 168
using Int64 = signed long;
using UInt64 = unsigned long;
169 170 171 172
#else
#error Could not find a 64-bit integer.
#endif

173
/// Represents an ID (index into arrays).
174
#ifdef VTKM_USE_64BIT_IDS
175
using Id = vtkm::Int64;
176
#else
177
using Id = vtkm::Int32;
178 179
#endif

180
/// The floating point type to use when no other precision is specified.
181
#ifdef VTKM_USE_DOUBLE_PRECISION
182
using FloatDefault = vtkm::Float64;
183
#else
184
using FloatDefault = vtkm::Float32;
185
#endif
186

187 188
namespace internal
{
189 190 191

//-----------------------------------------------------------------------------

192 193
/// Placeholder class for when a type is not applicable.
///
194
struct NullType
195 196 197
{
};

198 199
//-----------------------------------------------------------------------------
template <vtkm::IdComponent Size>
200 201
struct VecComponentWiseUnaryOperation
{
202
  template <typename T, typename UnaryOpType>
203
  inline VTKM_EXEC_CONT T operator()(const T& v, const UnaryOpType& unaryOp) const
204
  {
205
    T result;
206
    for (vtkm::IdComponent i = 0; i < Size; ++i)
207
    {
208
      result[i] = unaryOp(v[i]);
209
    }
210
    return result;
211
  }
212
};
213

214
template <>
215 216
struct VecComponentWiseUnaryOperation<1>
{
217
  template <typename T, typename UnaryOpType>
218
  inline VTKM_EXEC_CONT T operator()(const T& v, const UnaryOpType& unaryOp) const
219
  {
220
    return T(unaryOp(v[0]));
221
  }
222
};
223

224
template <>
225 226
struct VecComponentWiseUnaryOperation<2>
{
227
  template <typename T, typename UnaryOpType>
228
  inline VTKM_EXEC_CONT T operator()(const T& v, const UnaryOpType& unaryOp) const
229
  {
230
    return T(unaryOp(v[0]), unaryOp(v[1]));
231 232 233
  }
};

234
template <>
235
struct VecComponentWiseUnaryOperation<3>
236
{
237
  template <typename T, typename UnaryOpType>
238
  inline VTKM_EXEC_CONT T operator()(const T& v, const UnaryOpType& unaryOp) const
239
  {
240
    return T(unaryOp(v[0]), unaryOp(v[1]), unaryOp(v[2]));
241
  }
242
};
243

244
template <>
245 246
struct VecComponentWiseUnaryOperation<4>
{
247
  template <typename T, typename UnaryOpType>
248
  inline VTKM_EXEC_CONT T operator()(const T& v, const UnaryOpType& unaryOp) const
249
  {
250
    return T(unaryOp(v[0]), unaryOp(v[1]), unaryOp(v[2]), unaryOp(v[3]));
251
  }
252
};
253

254
template <typename T, typename BinaryOpType, typename ReturnT = T>
255 256 257
struct BindLeftBinaryOp
{
  // Warning: a reference.
258
  const T& LeftValue;
259
  const BinaryOpType BinaryOp;
260
  VTKM_EXEC_CONT
261 262 263 264 265
  BindLeftBinaryOp(const T& leftValue, BinaryOpType binaryOp = BinaryOpType())
    : LeftValue(leftValue)
    , BinaryOp(binaryOp)
  {
  }
Kenneth Moreland's avatar
Kenneth Moreland committed
266

267 268
  template <typename RightT>
  VTKM_EXEC_CONT ReturnT operator()(const RightT& rightValue) const
269
  {
270
    return static_cast<ReturnT>(this->BinaryOp(this->LeftValue, static_cast<T>(rightValue)));
271
  }
272 273

private:
274
  void operator=(const BindLeftBinaryOp<T, BinaryOpType, ReturnT>&) = delete;
275 276
};

277
template <typename T, typename BinaryOpType, typename ReturnT = T>
278
struct BindRightBinaryOp
279
{
280
  // Warning: a reference.
281
  const T& RightValue;
282
  const BinaryOpType BinaryOp;
283
  VTKM_EXEC_CONT
284 285 286 287 288
  BindRightBinaryOp(const T& rightValue, BinaryOpType binaryOp = BinaryOpType())
    : RightValue(rightValue)
    , BinaryOp(binaryOp)
  {
  }
Kenneth Moreland's avatar
Kenneth Moreland committed
289

290 291
  template <typename LeftT>
  VTKM_EXEC_CONT ReturnT operator()(const LeftT& leftValue) const
292
  {
293
    return static_cast<ReturnT>(this->BinaryOp(static_cast<T>(leftValue), this->RightValue));
294
  }
295 296

private:
297
  void operator=(const BindRightBinaryOp<T, BinaryOpType, ReturnT>&) = delete;
298
};
299

300 301
} // namespace internal

302 303 304 305 306 307
// Disable conversion warnings for Add, Subtract, Multiply, Divide on GCC only.
// GCC creates false positive warnings for signed/unsigned char* operations.
// This occurs because the values are implicitly casted up to int's for the
// operation, and than  casted back down to char's when return.
// This causes a false positive warning, even when the values is within
// the value types range
308
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
309 310 311
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#endif // gcc || clang
312 313
struct Add
{
314
  template <typename T>
315
  inline VTKM_EXEC_CONT T operator()(const T& a, const T& b) const
316
  {
317
    return T(a + b);
318
  }
319
};
320

321 322
struct Subtract
{
323
  template <typename T>
324
  inline VTKM_EXEC_CONT T operator()(const T& a, const T& b) const
325
  {
326
    return T(a - b);
327
  }
328 329 330 331
};

struct Multiply
{
332
  template <typename T>
333
  inline VTKM_EXEC_CONT T operator()(const T& a, const T& b) const
334
  {
335
    return T(a * b);
336
  }
337
};
338

339 340
struct Divide
{
341
  template <typename T>
342
  inline VTKM_EXEC_CONT T operator()(const T& a, const T& b) const
343
  {
344
    return T(a / b);
345 346 347
  }
};

348 349
struct Negate
{
350
  template <typename T>
351
  inline VTKM_EXEC_CONT T operator()(const T& x) const
352
  {
353
    return T(-x);
354 355 356
  }
};

357
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
358 359 360
#pragma GCC diagnostic pop
#endif // gcc || clang

361 362
//-----------------------------------------------------------------------------

363
// Pre declaration
364
template <typename T, vtkm::IdComponent Size>
365
class VTKM_ALWAYS_EXPORT Vec;
366

367
template <typename T>
368
class VTKM_ALWAYS_EXPORT VecC;
369

370
template <typename T>
371
class VTKM_ALWAYS_EXPORT VecCConst;
372

373 374
namespace detail
{
375

376
/// Base implementation of all Vec and VecC classes.
377
///
378 379 380 381 382 383 384
// Disable conversion warnings for Add, Subtract, Multiply, Divide on GCC only.
// GCC creates false positive warnings for signed/unsigned char* operations.
// This occurs because the values are implicitly casted up to int's for the
// operation, and than  casted back down to char's when return.
// This causes a false positive warning, even when the values is within
// the value types range
//
385
// NVCC 7.5 and below does not recognize this pragma inside of class bodies,
386 387 388 389 390
// so put them before entering the class.
//
#if (defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8))
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic push
391 392
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wpragmas"
393
#pragma GCC diagnostic ignored "-Wconversion"
394
#pragma GCC diagnostic ignored "-Wfloat-conversion"
395 396
#endif // gcc || clang
#endif // use cuda < 8
397
template <typename T, typename DerivedClass>
398
class VTKM_ALWAYS_EXPORT VecBaseCommon
399
{
400
public:
401
  using ComponentType = T;
402

403
protected:
404
  VecBaseCommon() = default;
405

406
  VTKM_EXEC_CONT
407
  const DerivedClass& Derived() const { return *static_cast<const DerivedClass*>(this); }
408

409
  VTKM_EXEC_CONT
410
  DerivedClass& Derived() { return *static_cast<DerivedClass*>(this); }
411

412 413
private:
  // Only for internal use
414
  VTKM_EXEC_CONT
415
  inline vtkm::IdComponent NumComponents() const { return this->Derived().GetNumberOfComponents(); }
416

417 418
  // Only for internal use
  VTKM_EXEC_CONT
419
  inline const T& Component(vtkm::IdComponent index) const { return this->Derived()[index]; }
420 421 422

  // Only for internal use
  VTKM_EXEC_CONT
423
  inline T& Component(vtkm::IdComponent index) { return this->Derived()[index]; }
424 425

public:
426
  template <vtkm::IdComponent OtherSize>
427
  VTKM_EXEC_CONT void CopyInto(vtkm::Vec<ComponentType, OtherSize>& dest) const
428
  {
429
    for (vtkm::IdComponent index = 0; (index < this->NumComponents()) && (index < OtherSize);
430
         index++)
431
    {
432
      dest[index] = this->Component(index);
433 434 435
    }
  }

436 437 438
  template <typename OtherComponentType, typename OtherVecType>
  VTKM_EXEC_CONT DerivedClass& operator=(
    const vtkm::detail::VecBaseCommon<OtherComponentType, OtherVecType>& src)
439
  {
440
    const OtherVecType& srcDerived = static_cast<const OtherVecType&>(src);
441 442
    VTKM_ASSERT(this->NumComponents() == srcDerived.GetNumberOfComponents());
    for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
443
    {
444
      this->Component(i) = OtherComponentType(srcDerived[i]);
445
    }
446
    return this->Derived();
447 448
  }

449
  VTKM_EXEC_CONT
450
  bool operator==(const DerivedClass& other) const
451
  {
452 453
    bool equal = true;
    for (vtkm::IdComponent i = 0; i < this->NumComponents() && equal; ++i)
454
    {
455
      equal = (this->Component(i) == other[i]);
456 457
    }
    return equal;
458
  }
459

460
  VTKM_EXEC_CONT
461
  bool operator<(const DerivedClass& other) const
462
  {
463
    for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
464
    {
465
      // ignore equals as that represents check next value
466
      if (this->Component(i) < other[i])
467 468 469
      {
        return true;
      }
470
      else if (other[i] < this->Component(i))
471 472 473
      {
        return false;
      }
474
    } // if all same we are not less
475 476

    return false;
477 478
  }

479
  VTKM_EXEC_CONT
480
  bool operator!=(const DerivedClass& other) const { return !(this->operator==(other)); }
481

482
#if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
483 484
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic push
485 486
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wpragmas"
487
#pragma GCC diagnostic ignored "-Wconversion"
488
#pragma GCC diagnostic ignored "-Wfloat-conversion"
489 490
#endif // gcc || clang
#endif // not using cuda < 8
491

492
  template <vtkm::IdComponent Size>
493
  inline VTKM_EXEC_CONT vtkm::Vec<ComponentType, Size> operator+(
494
    const vtkm::Vec<ComponentType, Size>& other) const
495
  {
496
    VTKM_ASSERT(Size == this->NumComponents());
497
    vtkm::Vec<ComponentType, Size> result;
498 499
    for (vtkm::IdComponent i = 0; i < Size; ++i)
    {
500
      result[i] = this->Component(i) + other[i];
501 502
    }
    return result;
503
  }
504

505
  template <typename OtherClass>
506 507
  inline VTKM_EXEC_CONT DerivedClass& operator+=(
    const VecBaseCommon<ComponentType, OtherClass>& other)
508
  {
509
    const OtherClass& other_derived = static_cast<const OtherClass&>(other);
510 511
    VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
    for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
512
    {
513
      this->Component(i) += other_derived[i];
514
    }
515
    return this->Derived();
516 517
  }

518
  template <vtkm::IdComponent Size>
519
  inline VTKM_EXEC_CONT vtkm::Vec<ComponentType, Size> operator-(
520
    const vtkm::Vec<ComponentType, Size>& other) const
521
  {
522
    VTKM_ASSERT(Size == this->NumComponents());
523
    vtkm::Vec<ComponentType, Size> result;
524 525
    for (vtkm::IdComponent i = 0; i < Size; ++i)
    {
526
      result[i] = this->Component(i) - other[i];
527 528
    }
    return result;
529
  }
530

531
  template <typename OtherClass>
532 533
  inline VTKM_EXEC_CONT DerivedClass& operator-=(
    const VecBaseCommon<ComponentType, OtherClass>& other)
534
  {
535
    const OtherClass& other_derived = static_cast<const OtherClass&>(other);
536 537
    VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
    for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
538
    {
539
      this->Component(i) -= other_derived[i];
540
    }
541
    return this->Derived();
542 543
  }

544
  template <vtkm::IdComponent Size>
545
  inline VTKM_EXEC_CONT vtkm::Vec<ComponentType, Size> operator*(
546
    const vtkm::Vec<ComponentType, Size>& other) const
547
  {
548
    vtkm::Vec<ComponentType, Size> result;
549 550
    for (vtkm::IdComponent i = 0; i < Size; ++i)
    {
551
      result[i] = this->Component(i) * other[i];
552 553
    }
    return result;
554
  }
555

556
  template <typename OtherClass>
557 558
  inline VTKM_EXEC_CONT DerivedClass& operator*=(
    const VecBaseCommon<ComponentType, OtherClass>& other)
559
  {
560
    const OtherClass& other_derived = static_cast<const OtherClass&>(other);
561 562
    VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
    for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
563
    {
564
      this->Component(i) *= other_derived[i];
565
    }
566
    return this->Derived();
567 568
  }

569
  template <vtkm::IdComponent Size>
570
  inline VTKM_EXEC_CONT vtkm::Vec<ComponentType, Size> operator/(
571
    const vtkm::Vec<ComponentType, Size>& other) const
572
  {
573
    vtkm::Vec<ComponentType, Size> result;
574 575
    for (vtkm::IdComponent i = 0; i < Size; ++i)
    {
576
      result[i] = this->Component(i) / other[i];
577 578 579 580
    }
    return result;
  }

581 582
  template <typename OtherClass>
  VTKM_EXEC_CONT DerivedClass& operator/=(const VecBaseCommon<ComponentType, OtherClass>& other)
583
  {
584
    const OtherClass& other_derived = static_cast<const OtherClass&>(other);
585 586
    VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
    for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
587
    {
588
      this->Component(i) /= other_derived[i];
589
    }
590
    return this->Derived();
591 592
  }

593
#if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
594 595
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic pop
596 597
#endif // gcc || clang
#endif // not using cuda < 8
598

599
  VTKM_EXEC_CONT
600
  ComponentType* GetPointer() { return &this->Component(0); }
601

602
  VTKM_EXEC_CONT
603
  const ComponentType* GetPointer() const { return &this->Component(0); }
604
};
605

606

607 608 609
/// Base implementation of all Vec classes.
///
template <typename T, vtkm::IdComponent Size, typename DerivedClass>
610
class VTKM_ALWAYS_EXPORT VecBase : public vtkm::detail::VecBaseCommon<T, DerivedClass>
611 612
{
public:
613
  using ComponentType = T;
614
  static constexpr vtkm::IdComponent NUM_COMPONENTS = Size;
615

616
  VecBase() = default;
617

618 619 620 621
  // The enable_if predicate will disable this constructor for Size=1 so that
  // the variadic constructor constexpr VecBase(T, Ts&&...) is called instead.
  template <vtkm::IdComponent Size2 = Size, typename std::enable_if<Size2 != 1, int>::type = 0>
  VTKM_EXEC_CONT explicit VecBase(const ComponentType& value)
622 623 624 625 626 627 628
  {
    for (vtkm::IdComponent i = 0; i < Size; ++i)
    {
      this->Components[i] = value;
    }
  }

629 630 631 632 633 634 635
  template <typename... Ts>
  VTKM_EXEC_CONT constexpr VecBase(ComponentType value0, Ts&&... values)
    : Components{ value0, values... }
  {
    VTKM_STATIC_ASSERT(sizeof...(Ts) + 1 == Size);
  }

636 637 638 639
  VTKM_EXEC_CONT
  VecBase(std::initializer_list<ComponentType> values)
  {
    ComponentType* dest = this->Components;
640 641
    auto src = values.begin();
    if (values.size() == 1)
642
    {
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
      for (vtkm::IdComponent i = 0; i < Size; ++i)
      {
        this->Components[i] = *src;
        ++dest;
      }
    }
    else
    {
      VTKM_ASSERT((values.size() == NUM_COMPONENTS) &&
                  "Vec object initialized wrong number of components.");
      for (; src != values.end(); ++src)
      {
        *dest = *src;
        ++dest;
      }
658 659 660
    }
  }

661 662 663 664 665 666 667 668 669 670 671 672 673 674
#if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif // gcc || clang
#endif //not using cuda < 8
#if defined(VTKM_MSVC)
#pragma warning(push)
#pragma warning(disable : 4244)
#endif

675
  template <typename OtherValueType, typename OtherDerivedType>
676
  VTKM_EXEC_CONT explicit VecBase(const VecBase<OtherValueType, Size, OtherDerivedType>& src)
677
  {
678 679
    //DO NOT CHANGE THIS AND THE ABOVE PRAGMA'S UNLESS YOU FULLY UNDERSTAND THE
    //ISSUE https://gitlab.kitware.com/vtk/vtk-m/issues/221
680 681
    for (vtkm::IdComponent i = 0; i < Size; ++i)
    {
682
      this->Components[i] = src[i];
683 684 685 686
    }
  }

public:
687
  inline VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const { return NUM_COMPONENTS; }
688

689
  inline VTKM_EXEC_CONT const ComponentType& operator[](vtkm::IdComponent idx) const
690 691
  {
    VTKM_ASSERT(idx >= 0);
692
    VTKM_ASSERT(idx < NUM_COMPONENTS);
693 694
    return this->Components[idx];
  }
695 696

  inline VTKM_EXEC_CONT ComponentType& operator[](vtkm::IdComponent idx)
697 698
  {
    VTKM_ASSERT(idx >= 0);
699
    VTKM_ASSERT(idx < NUM_COMPONENTS);
700 701 702 703
    return this->Components[idx];
  }


704
  template <typename OtherComponentType, typename OtherClass>
705
  inline VTKM_EXEC_CONT DerivedClass
706
  operator+(const VecBaseCommon<OtherComponentType, OtherClass>& other) const
707
  {
708
    const OtherClass& other_derived = static_cast<const OtherClass&>(other);
709 710 711 712 713
    VTKM_ASSERT(NUM_COMPONENTS == other_derived.GetNumberOfComponents());

    DerivedClass result;
    for (vtkm::IdComponent i = 0; i < NUM_COMPONENTS; ++i)
    {
714
      result[i] = this->Components[i] + static_cast<ComponentType>(other_derived[i]);
715 716 717 718
    }
    return result;
  }

719
  template <typename OtherComponentType, typename OtherClass>
720
  inline VTKM_EXEC_CONT DerivedClass
721
  operator-(const VecBaseCommon<OtherComponentType, OtherClass>& other) const
722
  {
723
    const OtherClass& other_derived = static_cast<const OtherClass&>(other);
724 725 726 727 728
    VTKM_ASSERT(NUM_COMPONENTS == other_derived.GetNumberOfComponents());

    DerivedClass result;
    for (vtkm::IdComponent i = 0; i < NUM_COMPONENTS; ++i)
    {
729
      result[i] = this->Components[i] - static_cast<ComponentType>(other_derived[i]);
730 731 732 733
    }
    return result;
  }

734
  template <typename OtherComponentType, typename OtherClass>
735
  inline VTKM_EXEC_CONT DerivedClass
736
  operator*(const VecBaseCommon<OtherComponentType, OtherClass>& other) const
737
  {
738
    const OtherClass& other_derived = static_cast<const OtherClass&>(other);
739 740 741 742 743
    VTKM_ASSERT(NUM_COMPONENTS == other_derived.GetNumberOfComponents());

    DerivedClass result;
    for (vtkm::IdComponent i = 0; i < NUM_COMPONENTS; ++i)
    {
744
      result[i] = this->Components[i] * static_cast<ComponentType>(other_derived[i]);
745 746 747 748
    }
    return result;
  }

749
  template <typename OtherComponentType, typename OtherClass>
750
  inline VTKM_EXEC_CONT DerivedClass
751
  operator/(const VecBaseCommon<OtherComponentType, OtherClass>& other) const
752
  {
753
    const OtherClass& other_derived = static_cast<const OtherClass&>(other);
754 755 756 757 758
    VTKM_ASSERT(NUM_COMPONENTS == other_derived.GetNumberOfComponents());

    DerivedClass result;
    for (vtkm::IdComponent i = 0; i < NUM_COMPONENTS; ++i)
    {
759
      result[i] = this->Components[i] / static_cast<ComponentType>(other_derived[i]);
760 761 762 763 764 765 766
    }
    return result;
  }

#if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic pop
767 768
#endif // gcc || clang
#endif // not using cuda < 8
769 770 771
#if defined(VTKM_MSVC)
#pragma warning(pop)
#endif
772 773 774 775 776

protected:
  ComponentType Components[NUM_COMPONENTS];
};

777 778 779 780 781 782
#if (defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8))
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic pop
#endif // gcc || clang
#endif // use cuda < 8

783 784 785
/// Base of all VecC and VecCConst classes.
///
template <typename T, typename DerivedClass>
786
class VTKM_ALWAYS_EXPORT VecCBase : public vtkm::detail::VecBaseCommon<T, DerivedClass>
787 788 789
{
protected:
  VTKM_EXEC_CONT
790
  VecCBase() {}
791 792
};

793
} // namespace detail
794

795 796 797 798 799 800 801 802 803 804
//-----------------------------------------------------------------------------

/// \brief A short fixed-length array.
///
/// The \c Vec templated class holds a short array of values of a size and
/// type specified by the template arguments.
///
/// The \c Vec class is most often used to represent vectors in the
/// mathematical sense as a quantity with a magnitude and direction. Vectors
/// are, of course, used extensively in computational geometry as well as
luz.paz's avatar
luz.paz committed
805
/// physical simulations. The \c Vec class can be (and is) repurposed for more
806 807 808 809 810 811
/// general usage of holding a fixed-length sequence of objects.
///
/// There is no real limit to the size of the sequence (other than the largest
/// number representable by vtkm::IdComponent), but the \c Vec class is really
/// designed for small sequences (seldom more than 10).
///
812 813
template <typename T, vtkm::IdComponent Size>
class VTKM_ALWAYS_EXPORT Vec : public detail::VecBase<T, Size, Vec<T, Size>>
814
{
815
  using Superclass = detail::VecBase<T, Size, Vec<T, Size>>;
816

817 818
public:
#ifdef VTKM_DOXYGEN_ONLY
819
  using ComponentType = T;
820
  static constexpr vtkm::IdComponent NUM_COMPONENTS = Size;
821 822
#endif

823
  using Superclass::Superclass;
824
  Vec() = default;
825 826 827 828
#if defined(_MSC_VER) && _MSC_VER < 1910
  template <typename... Ts>
  constexpr Vec(T value, Ts&&... values)
    : Superclass(value, std::forward<Ts>(values)...)
829 830
  {
  }
831
#endif
832 833

  inline VTKM_EXEC_CONT void CopyInto(Vec<T, Size>& dest) const { dest = *this; }
834
};
835

836 837 838 839 840 841
//-----------------------------------------------------------------------------
// Specializations for common small tuples. We implement them a bit specially.

// A vector of size 0 cannot use VecBase because it will try to create a
// zero length array which troubles compilers. Vecs of size 0 are a bit
// pointless but might occur in some generic functions or classes.
842
template <typename T>
843
class VTKM_ALWAYS_EXPORT Vec<T, 0>
844
{
845
public:
846
  using ComponentType = T;
847
  static constexpr vtkm::IdComponent NUM_COMPONENTS = 0;
848

849
  Vec() = default;
850
  VTKM_EXEC_CONT explicit Vec(const ComponentType&) {}
851

852 853 854 855
  template <typename OtherType>
  VTKM_EXEC_CONT Vec(const Vec<OtherType, NUM_COMPONENTS>&)
  {
  }
856

857
  VTKM_EXEC_CONT
858
  Vec<ComponentType, NUM_COMPONENTS>& operator=(const Vec<ComponentType, NUM_COMPONENTS>&)
859
  {
860
    return *this;
861 862
  }

863
  VTKM_EXEC_CONT
864
  ComponentType operator[](vtkm::IdComponent vtkmNotUsed(idx)) const { return ComponentType(); }
865

866
  VTKM_EXEC_CONT
867
  bool operator==(const Vec<T, NUM_COMPONENTS>& vtkmNotUsed(other)) const { return true; }
868
  VTKM_EXEC_CONT
869
  bool operator!=(const Vec<T, NUM_COMPONENTS>& vtkmNotUsed(other)) const { return false; }
870 871
};

872 873
// Vectors of size 1 should implicitly convert between the scalar and the
// vector. Otherwise, it should behave the same.
874 875
template <typename T>
class VTKM_ALWAYS_EXPORT Vec<T, 1> : public detail::VecBase<T, 1, Vec<T, 1>>
876
{
877
  using Superclass = detail::VecBase<T, 1, Vec<T, 1>>;
878 879

public:
880
  Vec() = default;
881
  VTKM_EXEC_CONT constexpr Vec(const T& value)
882 883 884
    : Superclass(value)
  {
  }
885

886 887 888 889 890
  template <typename OtherType>
  VTKM_EXEC_CONT Vec(const Vec<OtherType, 1>& src)
    : Superclass(src)
  {
  }
891 892
};

893 894 895
//-----------------------------------------------------------------------------
// Specializations for common tuple sizes (with special names).

896 897
template <typename T>
class VTKM_ALWAYS_EXPORT Vec<T, 2> : public detail::VecBase<T, 2, Vec<T, 2>>
898
{
899
  using Superclass = detail::VecBase<T, 2, Vec<T, 2>>;
900 901

public:
902
  Vec() = default;
903
  VTKM_EXEC_CONT Vec(const T& value)
904 905 906
    : Superclass(value)
  {
  }
907

908 909 910 911 912
  template <typename OtherType>
  VTKM_EXEC_CONT Vec(const Vec<OtherType, 2>& src)
    : Superclass(src)
  {
  }
913

914
  VTKM_EXEC_CONT
915 916
  constexpr Vec(const T& x, const T& y)
    : Superclass(x, y)
917 918
  {
  }
919 920 921
};

/// Id2 corresponds to a 2-dimensional index
922
using Id2 = vtkm::Vec<vtkm::Id, 2>;
923

924 925
template <typename T>
class VTKM_ALWAYS_EXPORT Vec<T, 3> : public detail::VecBase<T, 3, Vec<T, 3>>
926
{
927
  using Superclass = detail::VecBase<T, 3, Vec<T, 3>>;
928

929
public:
930
  Vec() = default;
931
  VTKM_EXEC_CONT Vec(const T& value)
932 933 934
    : Superclass(value)
  {
  }
935

936 937 938 939 940
  template <typename OtherType>
  VTKM_EXEC_CONT Vec(const Vec<OtherType, 3>& src)
    : Superclass(src)
  {
  }
941

942
  VTKM_EXEC_CONT
943 944
  constexpr Vec(const T& x, const T& y, const T& z)
    : Superclass(x, y, z)
945 946
  {
  }
947 948 949 950
};

/// Id3 corresponds to a 3-dimensional index for 3d arrays.  Note that
/// the precision of each index may be less than vtkm::Id.
951
using Id3 = vtkm::Vec<vtkm::Id, 3>;
952

953 954
template <typename T>
class VTKM_ALWAYS_EXPORT Vec<T, 4> : public detail::VecBase<T, 4, Vec<T, 4>>
955
{
956
  using Superclass = detail::VecBase<T, 4, Vec<T, 4>>;
957

958
public:
959
  Vec() = default;
960
  VTKM_EXEC_CONT Vec(const T& value)
961 962 963
    : Superclass(value)
  {
  }
964

965 966 967 968 969
  template <typename OtherType>
  VTKM_EXEC_CONT Vec(const Vec<OtherType, 4>& src)
    : Superclass(src)
  {
  }
970

971
  VTKM_EXEC_CONT
972 973
  constexpr Vec(const T& x, const T& y, const T& z, const T& w)
    : Superclass(x, y, z, w)
974 975 976 977
  {
  }
};

978 979
/// Initializes and returns a Vec containing all the arguments. The arguments should all be the
/// same type or compile issues will occur.
980
///
981
template <typename T, typename... Ts>
982 983
VTKM_EXEC_CONT constexpr vtkm::Vec<T, vtkm::IdComponent(sizeof...(Ts) + 1)> make_Vec(T value0,
                                                                                     Ts&&... args)
984
{
985
  return vtkm::Vec<T, vtkm::IdComponent(sizeof...(Ts) + 1)>(value0, T(args)...);
986 987
}

988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
/// \brief A Vec-like representation for short arrays.
///
/// The \c VecC class takes a short array of values and provides an interface
/// that mimics \c Vec. This provides a mechanism to treat C arrays like a \c
/// Vec. It is useful in situations where you want to use a \c Vec but the data
/// must come from elsewhere or in certain situations where the size cannot be
/// determined at compile time. In particular, \c Vec objects of different
/// sizes can potentially all be converted to a \c VecC of the same type.
///
/// Note that \c VecC holds a reference to an outside array given to it. If
/// that array gets destroyed (for example because the source goes out of
/// scope), the behavior becomes undefined.
///
/// You cannot use \c VecC with a const type in its template argument. For
/// example, you cannot declare <tt>VecC<const vtkm::Id></tt>. If you want a
/// non-mutable \c VecC, the \c VecCConst class (e.g.
/// <tt>VecCConst<vtkm::Id></tt>).
///
1006 1007
template <typename T>
class VTKM_ALWAYS_EXPORT VecC : public detail::VecCBase<T, VecC<T>>
1008
{
1009
  using Superclass = detail::VecCBase<T, VecC<T>>;
1010

1011 1012 1013
  VTKM_STATIC_ASSERT_MSG(std::is_const<T>::value == false,
                         "You cannot use VecC with a const type as its template argument. "
                         "Use either const VecC or VecCConst.");
1014 1015 1016 1017 1018 1019 1020 1021

public:
#ifdef VTKM_DOXYGEN_ONLY
  using ComponentType = T;
#endif

  VTKM_EXEC_CONT
  VecC()
1022 1023 1024 1025
    : Components(nullptr)
    , NumberOfComponents(0)
  {
  }
1026 1027

  VTKM_EXEC_CONT
1028 1029 1030 1031 1032
  VecC(T* array, vtkm::IdComponent size)
    : Components(array)
    , NumberOfComponents(size)
  {
  }
1033

1034 1035 1036 1037 1038 1039
  template <vtkm::IdComponent Size>
  VTKM_EXEC_CONT VecC(vtkm::Vec<T, Size>& src)
    : Components(src.GetPointer())
    , NumberOfComponents(Size)
  {
  }
1040 1041

  VTKM_EXEC_CONT
1042 1043 1044 1045 1046
  explicit VecC(T& src)
    : Components(&src)
    , NumberOfComponents(1)
  {
  }
1047 1048

  VTKM_EXEC_CONT
1049 1050 1051 1052 1053
  VecC(const VecC<T>& src)
    : Components(src.Components)
    , NumberOfComponents(src.NumberOfComponents)
  {
  }
1054

1055
  inline VTKM_EXEC_CONT const T& operator[](vtkm::IdComponent index) const
1056 1057 1058 1059 1060 1061
  {
    VTKM_ASSERT(index >= 0);
    VTKM_ASSERT(index < this->NumberOfComponents);
    return this->Components[index];
  }