Point Cloud Library (PCL)  1.14.0-dev
type_traits.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2020-, Open Perception, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of the copyright holder(s) nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 #pragma once
39 
40 #include <pcl/point_struct_traits.h> // for pcl::traits::POD, pcl::traits::name, pcl::traits::datatype, pcl::traits::offset
41 
42 #include <cstddef> // for std::size_t
43 #include <cstdint> // for std::uint8_t
44 
45 #include <functional> // for std::function, needed till C++17
46 #include <string> // for std::string
47 #include <type_traits> // for std::false_type, std::true_type
48 
49 namespace pcl
50 {
51  namespace deprecated
52  {
53  /** \class DeprecatedType
54  * \brief A dummy type to aid in template parameter deprecation
55  */
56  struct T {};
57  }
58 
59  namespace fields
60  {
61  // Tag types get put in this namespace
62  }
63 
64  namespace traits
65  {
66  namespace detail {
67  /**
68  * \brief Enumeration for different numerical types
69  *
70  * \details struct used to enable scope and implicit conversion to int
71  */
72  struct PointFieldTypes {
73  static const std::uint8_t INT8 = 1, UINT8 = 2,
74  INT16 = 3, UINT16 = 4,
75  INT32 = 5, UINT32 = 6,
76  FLOAT32 = 7, FLOAT64 = 8,
77  INT64 = 9, UINT64 = 10,
78  BOOL = 11;
79  };
80  } // namespace detail
81 
82  // Metafunction to return enum value representing a type
83  template<typename T> struct asEnum {};
84  template<> struct asEnum<bool> { static const std::uint8_t value = detail::PointFieldTypes::BOOL; };
85  template<> struct asEnum<std::int8_t> { static const std::uint8_t value = detail::PointFieldTypes::INT8; };
86  template<> struct asEnum<std::uint8_t> { static const std::uint8_t value = detail::PointFieldTypes::UINT8; };
87  template<> struct asEnum<std::int16_t> { static const std::uint8_t value = detail::PointFieldTypes::INT16; };
88  template<> struct asEnum<std::uint16_t> { static const std::uint8_t value = detail::PointFieldTypes::UINT16; };
89  template<> struct asEnum<std::int32_t> { static const std::uint8_t value = detail::PointFieldTypes::INT32; };
90  template<> struct asEnum<std::uint32_t> { static const std::uint8_t value = detail::PointFieldTypes::UINT32; };
91  template<> struct asEnum<std::int64_t> { static const std::uint8_t value = detail::PointFieldTypes::INT64; };
92  template<> struct asEnum<std::uint64_t> { static const std::uint8_t value = detail::PointFieldTypes::UINT64; };
93  template<> struct asEnum<float> { static const std::uint8_t value = detail::PointFieldTypes::FLOAT32; };
94  template<> struct asEnum<double> { static const std::uint8_t value = detail::PointFieldTypes::FLOAT64; };
95 
96  template<typename T>
97  static constexpr std::uint8_t asEnum_v = asEnum<T>::value;
98 
99  // Metafunction to return type of enum value
100  template<int> struct asType {};
101  template<> struct asType<detail::PointFieldTypes::BOOL> { using type = bool; };
102  template<> struct asType<detail::PointFieldTypes::INT8> { using type = std::int8_t; };
103  template<> struct asType<detail::PointFieldTypes::UINT8> { using type = std::uint8_t; };
104  template<> struct asType<detail::PointFieldTypes::INT16> { using type = std::int16_t; };
105  template<> struct asType<detail::PointFieldTypes::UINT16> { using type = std::uint16_t; };
106  template<> struct asType<detail::PointFieldTypes::INT32> { using type = std::int32_t; };
107  template<> struct asType<detail::PointFieldTypes::UINT32> { using type = std::uint32_t; };
108  template<> struct asType<detail::PointFieldTypes::INT64> { using type = std::int64_t; };
109  template<> struct asType<detail::PointFieldTypes::UINT64> { using type = std::uint64_t; };
110  template<> struct asType<detail::PointFieldTypes::FLOAT32> { using type = float; };
111  template<> struct asType<detail::PointFieldTypes::FLOAT64> { using type = double; };
112 
113  template<int index>
114  using asType_t = typename asType<index>::type;
115 
116  } // namespace traits
117 
118  /** \brief A helper functor that can copy a specific value if the given field exists.
119  *
120  * \note In order to actually copy the value an instance of this functor should be passed
121  * to a pcl::for_each_type loop. See the example below.
122  *
123  * \code
124  * PointInT p;
125  * bool exists;
126  * float value;
127  * using FieldList = typename pcl::traits::fieldList<PointInT>::type;
128  * pcl::for_each_type<FieldList> (pcl::CopyIfFieldExists<PointT, float> (p, "intensity", exists, value));
129  * \endcode
130  */
131  template <typename PointInT, typename OutT>
133  {
134  using Pod = typename traits::POD<PointInT>::type;
135 
136  /** \brief Constructor.
137  * \param[in] pt the input point
138  * \param[in] field the name of the field
139  * \param[out] exists set to true if the field exists, false otherwise
140  * \param[out] value the copied field value
141  */
142  CopyIfFieldExists (const PointInT &pt,
143  const std::string &field,
144  bool &exists,
145  OutT &value)
146  : pt_ (reinterpret_cast<const Pod&>(pt)), name_ (field), exists_ (exists), value_ (value)
147  {
148  exists_ = false;
149  }
150 
151  /** \brief Constructor.
152  * \param[in] pt the input point
153  * \param[in] field the name of the field
154  * \param[out] value the copied field value
155  */
156  CopyIfFieldExists (const PointInT &pt,
157  const std::string &field,
158  OutT &value)
159  : pt_ (reinterpret_cast<const Pod&>(pt)), name_ (field), exists_ (exists_tmp_), value_ (value)
160  {
161  }
162 
163  /** \brief Operator. Data copy happens here. */
164  template <typename Key> inline void
166  {
167  if (name_ == pcl::traits::name<PointInT, Key>::value)
168  {
169  exists_ = true;
170  using T = typename pcl::traits::datatype<PointInT, Key>::type;
171  const std::uint8_t* data_ptr = reinterpret_cast<const std::uint8_t*>(&pt_) + pcl::traits::offset<PointInT, Key>::value;
172  value_ = static_cast<OutT> (*reinterpret_cast<const T*>(data_ptr));
173  }
174  }
175 
176  private:
177  const Pod &pt_;
178  const std::string &name_;
179  bool &exists_;
180  // Bogus entry
181  bool exists_tmp_;
182  OutT &value_;
183  };
184 
185  /** \brief A helper functor that can set a specific value in a field if the field exists.
186  *
187  * \note In order to actually set the value an instance of this functor should be passed
188  * to a pcl::for_each_type loop. See the example below.
189  *
190  * \code
191  * PointT p;
192  * using FieldList = typename pcl::traits::fieldList<PointT>::type;
193  * pcl::for_each_type<FieldList> (pcl::SetIfFieldExists<PointT, float> (p, "intensity", 42.0f));
194  * \endcode
195  */
196  template <typename PointOutT, typename InT>
198  {
199  using Pod = typename traits::POD<PointOutT>::type;
200 
201  /** \brief Constructor.
202  * \param[in] pt the input point
203  * \param[in] field the name of the field
204  * \param[out] value the value to set
205  */
206  SetIfFieldExists (PointOutT &pt,
207  const std::string &field,
208  const InT &value)
209  : pt_ (reinterpret_cast<Pod&>(pt)), name_ (field), value_ (value)
210  {
211  }
212 
213  /** \brief Operator. Data copy happens here. */
214  template <typename Key> inline void
216  {
217  if (name_ == pcl::traits::name<PointOutT, Key>::value)
218  {
219  using T = typename pcl::traits::datatype<PointOutT, Key>::type;
220  std::uint8_t* data_ptr = reinterpret_cast<std::uint8_t*>(&pt_) + pcl::traits::offset<PointOutT, Key>::value;
221  *reinterpret_cast<T*>(data_ptr) = static_cast<T> (value_);
222  }
223  }
224 
225  private:
226  Pod &pt_;
227  const std::string &name_;
228  const InT &value_;
229  };
230 
231  /** \brief Set the value at a specified field in a point
232  * \param[out] pt the point to set the value to
233  * \param[in] field_offset the offset of the field
234  * \param[in] value the value to set
235  */
236  template <typename PointT, typename ValT> inline void
237  setFieldValue (PointT &pt, std::size_t field_offset, const ValT &value)
238  {
239  std::uint8_t* data_ptr = reinterpret_cast<std::uint8_t*>(&pt) + field_offset;
240  *reinterpret_cast<ValT*>(data_ptr) = value;
241  }
242 
243  /** \brief Get the value at a specified field in a point
244  * \param[in] pt the point to get the value from
245  * \param[in] field_offset the offset of the field
246  * \param[out] value the value to retrieve
247  */
248  template <typename PointT, typename ValT> inline void
249  getFieldValue (const PointT &pt, std::size_t field_offset, ValT &value)
250  {
251  const std::uint8_t* data_ptr = reinterpret_cast<const std::uint8_t*>(&pt) + field_offset;
252  value = *reinterpret_cast<const ValT*>(data_ptr);
253  }
254 
255  template <typename ...> using void_t = void; // part of std in c++17
256 
257 #ifdef DOXYGEN_ONLY
258 
259  /**
260  * \brief Tests at compile time if type T has a custom allocator
261  *
262  * \see pcl::make_shared, PCL_MAKE_ALIGNED_OPERATOR_NEW
263  * \tparam T Type of the object to test
264  */
265  template <typename T> struct has_custom_allocator;
266 
267 #else
268 
269  template <typename, typename = void_t<>> struct has_custom_allocator : std::false_type {};
270  template <typename T> struct has_custom_allocator<T, void_t<typename T::_custom_allocator_type_trait>> : std::true_type {};
271 
272 #endif
273 
274  /**
275  * \todo: Remove in C++17
276  */
277 #ifndef __cpp_lib_is_invocable
278  // Implementation taken from: https://stackoverflow.com/a/51188325
279  template <typename F, typename... Args>
280  constexpr bool is_invocable_v =
281  std::is_constructible<std::function<void(Args...)>,
282  std::reference_wrapper<std::remove_reference_t<F>>>::value;
283 
284  template <typename R, typename F, typename... Args>
285  constexpr bool is_invocable_r_v =
286  std::is_constructible<std::function<R(Args...)>,
287  std::reference_wrapper<std::remove_reference_t<F>>>::value;
288 #else
289  using std::is_invocable_v;
290  using std::is_invocable_r_v;
291 #endif
292 
293  /**
294  * \todo: Remove in C++17
295  */
296 #ifndef __cpp_lib_remove_cvref
297  template <typename T>
298  using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
299 #else
300  using std::remove_cvref_t;
301 #endif
302 }
typename asType< index >::type asType_t
Definition: type_traits.h:114
static constexpr std::uint8_t asEnum_v
Definition: type_traits.h:97
void setFieldValue(PointT &pt, std::size_t field_offset, const ValT &value)
Set the value at a specified field in a point.
Definition: type_traits.h:237
constexpr bool is_invocable_v
Definition: type_traits.h:280
void getFieldValue(const PointT &pt, std::size_t field_offset, ValT &value)
Get the value at a specified field in a point.
Definition: type_traits.h:249
std::remove_cv_t< std::remove_reference_t< T > > remove_cvref_t
Definition: type_traits.h:298
constexpr bool is_invocable_r_v
Definition: type_traits.h:285
void void_t
Definition: type_traits.h:255
A helper functor that can copy a specific value if the given field exists.
Definition: type_traits.h:133
CopyIfFieldExists(const PointInT &pt, const std::string &field, OutT &value)
Constructor.
Definition: type_traits.h:156
CopyIfFieldExists(const PointInT &pt, const std::string &field, bool &exists, OutT &value)
Constructor.
Definition: type_traits.h:142
void operator()()
Operator.
Definition: type_traits.h:165
typename traits::POD< PointInT >::type Pod
Definition: type_traits.h:134
A point structure representing Euclidean xyz coordinates, and the RGB color.
A helper functor that can set a specific value in a field if the field exists.
Definition: type_traits.h:198
SetIfFieldExists(PointOutT &pt, const std::string &field, const InT &value)
Constructor.
Definition: type_traits.h:206
typename traits::POD< PointOutT >::type Pod
Definition: type_traits.h:199
void operator()()
Operator.
Definition: type_traits.h:215
Tests at compile time if type T has a custom allocator.
Definition: type_traits.h:265
Enumeration for different numerical types.
Definition: type_traits.h:72
static const std::uint8_t INT16
Definition: type_traits.h:74
static const std::uint8_t INT64
Definition: type_traits.h:77
static const std::uint8_t FLOAT64
Definition: type_traits.h:76
static const std::uint8_t UINT64
Definition: type_traits.h:77
static const std::uint8_t UINT8
Definition: type_traits.h:73
static const std::uint8_t UINT32
Definition: type_traits.h:75
static const std::uint8_t BOOL
Definition: type_traits.h:78
static const std::uint8_t FLOAT32
Definition: type_traits.h:76
static const std::uint8_t INT32
Definition: type_traits.h:75
static const std::uint8_t UINT16
Definition: type_traits.h:74
static const std::uint8_t INT8
Definition: type_traits.h:73