treelite
common.h
Go to the documentation of this file.
1 
7 #ifndef TREELITE_COMMON_H_
8 #define TREELITE_COMMON_H_
9 
10 #include <treelite/base.h>
11 #include <dmlc/logging.h>
12 #include <dmlc/json.h>
13 #include <dmlc/data.h>
14 #include <memory>
15 #include <iterator>
16 #include <functional>
17 #include <cerrno>
18 #include <climits>
19 
20 namespace treelite {
21 namespace common {
22 
24 class Cloneable {
25  public:
26  virtual ~Cloneable() = default;
27  virtual Cloneable* clone() const = 0; // for copy operation
28  virtual Cloneable* move_clone() = 0; // for move operation
29 };
30 
32 #define CLONEABLE_BOILERPLATE(className) \
33  explicit className(const className& other) = default; \
34  explicit className(className&& other) = default; \
35  Cloneable* clone() const override { \
36  return new className(*this); \
37  } \
38  Cloneable* move_clone() override { \
39  return new className(std::move(*this)); \
40  }
41 
46 template <typename T>
48  public:
49  static_assert(std::is_base_of<Cloneable, T>::value,
50  "DeepCopyUniquePtr requires a Cloneable type");
51  ~DeepCopyUniquePtr() {}
52 
53  explicit DeepCopyUniquePtr(const T& other)
54  : ptr(dynamic_cast<T*>(other.clone())) {}
55  // downcasting is okay here because the other object is certainly of type T
56  explicit DeepCopyUniquePtr(T&& other)
57  : ptr(dynamic_cast<T*>(other.move_clone())) {}
58  explicit DeepCopyUniquePtr(const DeepCopyUniquePtr<T>& other)
59  : ptr(dynamic_cast<T*>(other.ptr->clone())) {}
60  explicit DeepCopyUniquePtr(DeepCopyUniquePtr<T>&& other)
61  : ptr(std::move(other.ptr)) {}
62 
63  inline T& operator*() {
64  return *ptr;
65  }
66  const inline T& operator*() const {
67  return *ptr;
68  }
69  T* operator->() {
70  return ptr.operator->();
71  }
72  const T* operator->() const {
73  return ptr.operator->();
74  }
75 
76  private:
77  std::unique_ptr<T> ptr;
78 };
79 
89 template<typename T, typename ...Args>
90 std::unique_ptr<T> make_unique(Args&& ...args)
91 {
92  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
93 }
94 
108 template <typename T>
109 inline T&& MoveUniquePtr(const std::unique_ptr<T>& ptr) {
110  return std::move(*ptr.get());
111 }
112 
123 inline void WrapText(std::ostringstream* p_stm, size_t* p_length,
124  const std::string& str, size_t textwidth) {
125  std::ostringstream& stm = *p_stm;
126  size_t& length = *p_length;
127  if (length + str.length() + 2 <= textwidth) {
128  stm << str << ", ";
129  length += str.length() + 2;
130  } else {
131  stm << "\n " << str << ", ";
132  length = str.length() + 4;
133  }
134 }
135 
145 template<class Iter, class T>
146 Iter binary_search(Iter begin, Iter end, const T& val)
147 {
148  Iter i = std::lower_bound(begin, end, val);
149  if (i != end && !(val < *i)) {
150  return i; // found
151  } else {
152  return end; // not found
153  }
154 }
155 
161 template <typename T>
162 inline std::string ToString(T value) {
163  std::ostringstream oss;
164  oss << value;
165  return oss.str();
166 }
167 
175 inline void WriteToFile(const std::string& filename,
176  const std::vector<std::string>& lines) {
177  std::unique_ptr<dmlc::Stream> fo(dmlc::Stream::Create(filename.c_str(), "w"));
178  dmlc::ostream os(fo.get());
179  std::copy(lines.begin(), lines.end(),
180  std::ostream_iterator<std::string>(os, "\n"));
181  // force flush before fo destruct.
182  os.set_stream(nullptr);
183 }
184 
192 inline void TransformPushBack(std::vector<std::string>* p_dest,
193  const std::vector<std::string>& lines,
194  std::function<std::string(std::string)> func) {
195  auto& dest = *p_dest;
196  std::transform(lines.begin(), lines.end(), std::back_inserter(dest), func);
197 }
198 
205 template <typename T>
206 inline T TextToNumber(const std::string& str) {
207  static_assert(std::is_same<T, float>::value
208  || std::is_same<T, double>::value
209  || std::is_same<T, int>::value
210  || std::is_same<T, int8_t>::value
211  || std::is_same<T, uint32_t>::value,
212  "unsupported data type for TextToNumber; use float, double, "
213  "int, int8_t, or uint32_t.");
214 }
215 
216 template <>
217 inline float TextToNumber(const std::string& str) {
218  errno = 0;
219  char *endptr;
220  float val = std::strtof(str.c_str(), &endptr);
221  if (errno == ERANGE) {
222  LOG(FATAL) << "Range error while converting string to double";
223  }
224  else if (errno != 0) {
225  LOG(FATAL) << "Unknown error";
226  }
227  else if (*endptr != '\0') {
228  LOG(FATAL) << "String does not represent a valid floating-point number";
229  }
230  return val;
231 }
232 
233 template <>
234 inline double TextToNumber(const std::string& str) {
235  errno = 0;
236  char *endptr;
237  double val = std::strtod(str.c_str(), &endptr);
238  if (errno == ERANGE) {
239  LOG(FATAL) << "Range error while converting string to double";
240  }
241  else if (errno != 0) {
242  LOG(FATAL) << "Unknown error";
243  }
244  else if (*endptr != '\0') {
245  LOG(FATAL) << "String does not represent a valid floating-point number";
246  }
247  return val;
248 }
249 
250 template <>
251 inline int TextToNumber(const std::string& str) {
252  errno = 0;
253  char *endptr;
254  long int val = std::strtol(str.c_str(), &endptr, 10);
255  if (errno == ERANGE || val < INT_MIN || val > INT_MAX) {
256  LOG(FATAL) << "Range error while converting string to int";
257  }
258  else if (errno != 0) {
259  LOG(FATAL) << "Unknown error";
260  }
261  else if (*endptr != '\0') {
262  LOG(FATAL) << "String does not represent a valid integer";
263  }
264  return static_cast<int>(val);
265 }
266 
267 template <>
268 inline int8_t TextToNumber(const std::string& str) {
269  errno = 0;
270  char *endptr;
271  long int val = std::strtol(str.c_str(), &endptr, 10);
272  if (errno == ERANGE || val < INT8_MIN || val > INT8_MAX) {
273  LOG(FATAL) << "Range error while converting string to int8_t";
274  }
275  else if (errno != 0) {
276  LOG(FATAL) << "Unknown error";
277  }
278  else if (*endptr != '\0') {
279  LOG(FATAL) << "String does not represent a valid integer";
280  }
281  return static_cast<int8_t>(val);
282 }
283 
284 template <>
285 inline uint32_t TextToNumber(const std::string& str) {
286  static_assert(sizeof(uint32_t) <= sizeof(unsigned long int),
287  "unsigned long int too small to hold uint32_t");
288  errno = 0;
289  char *endptr;
290  unsigned long int val = std::strtoul(str.c_str(), &endptr, 10);
291  if (errno == ERANGE || val > UINT32_MAX) {
292  LOG(FATAL) << "Range error while converting string to uint32_t";
293  }
294  else if (errno != 0) {
295  LOG(FATAL) << "Unknown error";
296  }
297  else if (*endptr != '\0') {
298  LOG(FATAL) << "String does not represent a valid integer";
299  }
300  return static_cast<uint32_t>(val);
301 }
302 
309 template <typename T>
310 inline std::vector<T> TextToArray(const std::string& text, int num_entry) {
311  std::vector<T> array;
312  std::istringstream ss(text);
313  std::string token;
314  for (int i = 0; i < num_entry; ++i) {
315  std::getline(ss, token, ' ');
316  array.push_back(TextToNumber<T>(token));
317  }
318  return array;
319 }
320 
327 inline std::vector<std::string> Split(const std::string& text, char delim) {
328  std::vector<std::string> array;
329  std::istringstream ss(text);
330  std::string token;
331  while (std::getline(ss, token, delim)) {
332  array.push_back(token);
333  }
334  return array;
335 }
336 
337 } // namespace common
338 } // namespace treelite
339 #endif // TREELITE_COMMON_H_
std::vector< T > TextToArray(const std::string &text, int num_entry)
convert text to number array
Definition: common.h:310
void WriteToFile(const std::string &filename, const std::vector< std::string > &lines)
write a sequence of strings to a text file, with newline character ( ) inserted between strings...
Definition: common.h:175
void TransformPushBack(std::vector< std::string > *p_dest, const std::vector< std::string > &lines, std::function< std::string(std::string)> func)
apply a given transformation to a sequence of strings and append them to another sequence.
Definition: common.h:192
std::string ToString(T value)
obtain a string representation of primitive type using ostringstream
Definition: common.h:162
abstract interface for classes that can be cloned
Definition: common.h:24
a wrapper around std::unique_ptr that supports deep copying and moving.
Definition: common.h:47
std::vector< std::string > Split(const std::string &text, char delim)
split text using a delimiter
Definition: common.h:327
Iter binary_search(Iter begin, Iter end, const T &val)
perform binary search on the range [begin, end).
Definition: common.h:146
defines configuration macros of treelite
void WrapText(std::ostringstream *p_stm, size_t *p_length, const std::string &str, size_t textwidth)
insert a string into a string stream, adding a newline character ( ) so that the string stream has no...
Definition: common.h:123
T && MoveUniquePtr(const std::unique_ptr< T > &ptr)
utility function to move an object pointed by a std::unique_ptr. After the move operation, the unique_ptr will hold an invalid object. Usage example:
Definition: common.h:109
std::unique_ptr< T > make_unique(Args &&...args)
construct a new object of type T and wraps it with a std::unique_ptr. This is support legacy compiles...
Definition: common.h:90
T TextToNumber(const std::string &str)
convert text to number
Definition: common.h:206