ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Scalar.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #pragma once
9 
10 #include <Logging.h>
11 
12 #include <cstdint>
13 #include <limits>
14 #include <string>
15 
16 #include "cloudViewer/core/Dtype.h"
17 
18 namespace cloudViewer {
19 namespace core {
20 
24 class Scalar {
25 public:
26  enum class ScalarType { Double, Int64, Bool };
27 
28  Scalar(float v) {
29  scalar_type_ = ScalarType::Double;
30  value_.d = static_cast<double>(v);
31  }
32  Scalar(double v) {
33  scalar_type_ = ScalarType::Double;
34  value_.d = static_cast<double>(v);
35  }
36  Scalar(int8_t v) {
37  scalar_type_ = ScalarType::Int64;
38  value_.i = static_cast<int64_t>(v);
39  }
40  Scalar(int16_t v) {
41  scalar_type_ = ScalarType::Int64;
42  value_.i = static_cast<int64_t>(v);
43  }
44  Scalar(int32_t v) {
45  scalar_type_ = ScalarType::Int64;
46  value_.i = static_cast<int64_t>(v);
47  }
48  Scalar(int64_t v) {
49  scalar_type_ = ScalarType::Int64;
50  value_.i = static_cast<int64_t>(v);
51  }
52 
53  // This constructor is required to ensure long input support where int64_t
54  // is not equal to long (e.g. mac os where int64_t is long long).
55  // The template argument with enable_if ensures that this constructor is
56  // enabled only when int64_t is not equal to long.
57  // Ref: https://en.cppreference.com/w/cpp/types/enable_if
58  template <typename T = int64_t>
59  Scalar(long v,
60  typename std::enable_if<!std::is_same<T, long>::value>::type* = 0) {
61  scalar_type_ = ScalarType::Int64;
62  value_.i = static_cast<int64_t>(v);
63  }
64  Scalar(uint8_t v) {
65  scalar_type_ = ScalarType::Int64;
66  value_.i = static_cast<int64_t>(v);
67  }
68  Scalar(uint16_t v) {
69  scalar_type_ = ScalarType::Int64;
70  value_.i = static_cast<int64_t>(v);
71  }
72  Scalar(uint32_t v) {
73  scalar_type_ = ScalarType::Int64;
74  value_.i = static_cast<int64_t>(v);
75  }
76  Scalar(uint64_t v) {
77  scalar_type_ = ScalarType::Int64;
78  // Conversion uint64_t -> int64_t is undefined behaviour until C++20.
79  // Compilers optimize this to a single cast.
80  if (v <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
81  value_.i = static_cast<int64_t>(v);
82  } else {
83  // Safe conversion to two's complement:
84  // - Compute x = uint_max - v such that x <= int_max
85  // - Safely cast x from unsigned to signed
86  // - Map x to y such that casting y to signed leads y = v
87  value_.i = -static_cast<int64_t>(
89  1;
90  }
91  }
92  Scalar(bool v) {
93  scalar_type_ = ScalarType::Bool;
94  value_.b = static_cast<bool>(v);
95  }
96 
97  bool IsDouble() const { return scalar_type_ == ScalarType::Double; }
98  bool IsInt64() const { return scalar_type_ == ScalarType::Int64; }
99  bool IsBool() const { return scalar_type_ == ScalarType::Bool; }
100 
103  double GetDouble() const {
104  if (!IsDouble()) {
105  utility::LogError("Scalar is not a ScalarType:Double type.");
106  }
107  return value_.d;
108  }
111  int64_t GetInt64() const {
112  if (!IsInt64()) {
113  utility::LogError("Scalar is not a ScalarType:Int64 type.");
114  }
115  return value_.i;
116  }
119  bool GetBool() const {
120  if (!IsBool()) {
121  utility::LogError("Scalar is not a ScalarType:Bool type.");
122  }
123  return value_.b;
124  }
125 
127  template <typename T>
128  T To() const {
129  if (scalar_type_ == ScalarType::Double) {
130  return static_cast<T>(value_.d);
131  } else if (scalar_type_ == ScalarType::Int64) {
132  return static_cast<T>(value_.i);
133  } else if (scalar_type_ == ScalarType::Bool) {
134  return static_cast<T>(value_.b);
135  } else {
136  utility::LogError("To: ScalarType not supported.");
137  }
138  }
139 
141  const std::string& error_msg) const {
142  if (scalar_type_ != other.scalar_type_) {
143  if (error_msg.empty()) {
144  utility::LogError("Scalar mode {} are not the same as {}.",
145  ToString(), other.ToString());
146  } else {
147  utility::LogError("Scalar mode {} are not the same as {}: {}",
148  ToString(), other.ToString(), error_msg);
149  }
150  }
151  }
152 
153  std::string ToString() const {
154  std::string scalar_type_str;
155  std::string value_str;
156  if (scalar_type_ == ScalarType::Double) {
157  scalar_type_str = "Double";
158  value_str = std::to_string(value_.d);
159  } else if (scalar_type_ == ScalarType::Int64) {
160  scalar_type_str = "Int64";
161  value_str = std::to_string(value_.i);
162  } else if (scalar_type_ == ScalarType::Bool) {
163  scalar_type_str = "Bool";
164  value_str = value_.b ? "true" : "false";
165  } else {
166  utility::LogError("ScalarTypeToString: ScalarType not supported.");
167  }
168  return scalar_type_str + ":" + value_str;
169  }
170 
171  template <typename T>
172  bool Equal(T value) const {
173  if (scalar_type_ == ScalarType::Double) {
174  return value_.d == value;
175  } else if (scalar_type_ == ScalarType::Int64) {
176  return value_.i == value;
177  } else if (scalar_type_ == ScalarType::Bool) {
178  return false; // Boolean does not equal to non-boolean values.
179  } else {
180  utility::LogError("Equals: ScalarType not supported.");
181  }
182  }
183 
184  bool Equal(bool value) const {
185  return scalar_type_ == ScalarType::Bool && value_.b == value;
186  }
187 
188  bool Equal(Scalar other) const {
189  if (other.scalar_type_ == ScalarType::Double) {
190  return Equal(other.GetDouble());
191  } else if (other.scalar_type_ == ScalarType::Int64) {
192  return Equal(other.GetInt64());
193  } else if (other.scalar_type_ == ScalarType::Bool) {
194  return scalar_type_ == ScalarType::Bool &&
195  value_.b == other.value_.b;
196  } else {
197  utility::LogError("Equals: ScalarType not supported.");
198  }
199  }
200 
201 private:
202  ScalarType scalar_type_;
203  union value_t {
204  double d;
205  int64_t i;
206  bool b;
207  } value_;
208 };
209 
210 } // namespace core
211 } // namespace cloudViewer
char type
bool IsInt64() const
Definition: Scalar.h:98
std::string ToString() const
Definition: Scalar.h:153
Scalar(uint32_t v)
Definition: Scalar.h:72
bool GetBool() const
Definition: Scalar.h:119
double GetDouble() const
Definition: Scalar.h:103
bool IsBool() const
Definition: Scalar.h:99
bool Equal(bool value) const
Definition: Scalar.h:184
Scalar(long v, typename std::enable_if<!std::is_same< T, long >::value >::type *=0)
Definition: Scalar.h:59
bool Equal(Scalar other) const
Definition: Scalar.h:188
void AssertSameScalarType(Scalar other, const std::string &error_msg) const
Definition: Scalar.h:140
Scalar(uint64_t v)
Definition: Scalar.h:76
Scalar(uint16_t v)
Definition: Scalar.h:68
bool IsDouble() const
Definition: Scalar.h:97
T To() const
To<T>() does not check for scalar type and overflows.
Definition: Scalar.h:128
int64_t GetInt64() const
Definition: Scalar.h:111
bool Equal(T value) const
Definition: Scalar.h:172
#define LogError(...)
Definition: Logging.h:60
int max(int a, int b)
Definition: cutil_math.h:48
Generic file read and write utility for python interface.
std::string to_string(const T &n)
Definition: Common.h:20
unsigned Bool
Definition: sqlite3.c:20710