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 <iomanip>
18 #include <cerrno>
19 #include <climits>
20 
21 namespace treelite {
22 namespace common {
23 
25 class Cloneable {
26  public:
27  virtual ~Cloneable() = default;
28  virtual Cloneable* clone() const = 0; // for copy operation
29  virtual Cloneable* move_clone() = 0; // for move operation
30 };
31 
33 #define CLONEABLE_BOILERPLATE(className) \
34  explicit className(const className& other) = default; \
35  explicit className(className&& other) = default; \
36  Cloneable* clone() const override { \
37  return new className(*this); \
38  } \
39  Cloneable* move_clone() override { \
40  return new className(std::move(*this)); \
41  }
42 
47 template <typename T>
49  public:
50  static_assert(std::is_base_of<Cloneable, T>::value,
51  "DeepCopyUniquePtr requires a Cloneable type");
52  ~DeepCopyUniquePtr() {}
53 
54  explicit DeepCopyUniquePtr(const T& other)
55  : ptr(dynamic_cast<T*>(other.clone())) {}
56  // downcasting is okay here because the other object is certainly of type T
57  explicit DeepCopyUniquePtr(T&& other)
58  : ptr(dynamic_cast<T*>(other.move_clone())) {}
59  explicit DeepCopyUniquePtr(const DeepCopyUniquePtr<T>& other)
60  : ptr(dynamic_cast<T*>(other.ptr->clone())) {}
61  explicit DeepCopyUniquePtr(DeepCopyUniquePtr<T>&& other)
62  : ptr(std::move(other.ptr)) {}
63 
64  inline T& operator*() {
65  return *ptr;
66  }
67  const inline T& operator*() const {
68  return *ptr;
69  }
70  T* operator->() {
71  return ptr.operator->();
72  }
73  const T* operator->() const {
74  return ptr.operator->();
75  }
76 
77  private:
78  std::unique_ptr<T> ptr;
79 };
80 
90 template<typename T, typename ...Args>
91 std::unique_ptr<T> make_unique(Args&& ...args) {
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 
124 inline void WrapText(std::ostringstream* p_stm, size_t* p_length,
125  const std::string& str, size_t indent,
126  size_t textwidth) {
127  std::ostringstream& stm = *p_stm;
128  size_t& length = *p_length;
129  if (length + str.length() <= textwidth) {
130  stm << str;
131  length += str.length();
132  } else {
133  stm << "\n" << std::string(indent, ' ') << str;
134  length = str.length() + indent;
135  }
136 }
137 
147 template<class Iter, class T>
148 Iter binary_search(Iter begin, Iter end, const T& val)
149 {
150  Iter i = std::lower_bound(begin, end, val);
151  if (i != end && !(val < *i)) {
152  return i; // found
153  } else {
154  return end; // not found
155  }
156 }
157 
163 template <typename T>
164 inline std::string ToString(T value) {
165  std::ostringstream oss;
166  // to restore default precision
167  const std::streamsize ss = std::cout.precision();
168  oss << std::setprecision(std::numeric_limits<T>::digits10 + 2) << value
169  << std::setprecision(ss);
170  return oss.str();
171 }
172 
180 inline void WriteToFile(const std::string& filename,
181  const std::string& content) {
182  std::unique_ptr<dmlc::Stream> fo(dmlc::Stream::Create(filename.c_str(), "w"));
183  dmlc::ostream os(fo.get());
184  os << content;
185  // force flush before fo destruct.
186  os.set_stream(nullptr);
187 }
188 
196 inline void TransformPushBack(std::vector<std::string>* p_dest,
197  const std::vector<std::string>& lines,
198  std::function<std::string(std::string)> func) {
199  auto& dest = *p_dest;
200  std::transform(lines.begin(), lines.end(), std::back_inserter(dest), func);
201 }
202 
209 template <typename T>
210 inline T TextToNumber(const std::string& str) {
211  static_assert(std::is_same<T, float>::value
212  || std::is_same<T, double>::value
213  || std::is_same<T, int>::value
214  || std::is_same<T, int8_t>::value
215  || std::is_same<T, uint32_t>::value,
216  "unsupported data type for TextToNumber; use float, double, "
217  "int, int8_t, or uint32_t.");
218 }
219 
220 template <>
221 inline float TextToNumber(const std::string& str) {
222  errno = 0;
223  char *endptr;
224  float val = std::strtof(str.c_str(), &endptr);
225  if (errno == ERANGE) {
226  LOG(FATAL) << "Range error while converting string to double";
227  }
228  else if (errno != 0) {
229  LOG(FATAL) << "Unknown error";
230  }
231  else if (*endptr != '\0') {
232  LOG(FATAL) << "String does not represent a valid floating-point number";
233  }
234  return val;
235 }
236 
237 template <>
238 inline double TextToNumber(const std::string& str) {
239  errno = 0;
240  char *endptr;
241  double val = std::strtod(str.c_str(), &endptr);
242  if (errno == ERANGE) {
243  LOG(FATAL) << "Range error while converting string to double";
244  }
245  else if (errno != 0) {
246  LOG(FATAL) << "Unknown error";
247  }
248  else if (*endptr != '\0') {
249  LOG(FATAL) << "String does not represent a valid floating-point number";
250  }
251  return val;
252 }
253 
254 template <>
255 inline int TextToNumber(const std::string& str) {
256  errno = 0;
257  char *endptr;
258  long int val = std::strtol(str.c_str(), &endptr, 10);
259  if (errno == ERANGE || val < INT_MIN || val > INT_MAX) {
260  LOG(FATAL) << "Range error while converting string to int";
261  }
262  else if (errno != 0) {
263  LOG(FATAL) << "Unknown error";
264  }
265  else if (*endptr != '\0') {
266  LOG(FATAL) << "String does not represent a valid integer";
267  }
268  return static_cast<int>(val);
269 }
270 
271 template <>
272 inline int8_t TextToNumber(const std::string& str) {
273  errno = 0;
274  char *endptr;
275  long int val = std::strtol(str.c_str(), &endptr, 10);
276  if (errno == ERANGE || val < INT8_MIN || val > INT8_MAX) {
277  LOG(FATAL) << "Range error while converting string to int8_t";
278  }
279  else if (errno != 0) {
280  LOG(FATAL) << "Unknown error";
281  }
282  else if (*endptr != '\0') {
283  LOG(FATAL) << "String does not represent a valid integer";
284  }
285  return static_cast<int8_t>(val);
286 }
287 
288 template <>
289 inline uint32_t TextToNumber(const std::string& str) {
290  static_assert(sizeof(uint32_t) <= sizeof(unsigned long int),
291  "unsigned long int too small to hold uint32_t");
292  errno = 0;
293  char *endptr;
294  unsigned long int val = std::strtoul(str.c_str(), &endptr, 10);
295  if (errno == ERANGE || val > UINT32_MAX) {
296  LOG(FATAL) << "Range error while converting string to uint32_t";
297  }
298  else if (errno != 0) {
299  LOG(FATAL) << "Unknown error";
300  }
301  else if (*endptr != '\0') {
302  LOG(FATAL) << "String does not represent a valid integer";
303  }
304  return static_cast<uint32_t>(val);
305 }
306 
313 template <typename T>
314 inline std::vector<T> TextToArray(const std::string& text, int num_entry) {
315  std::vector<T> array;
316  std::istringstream ss(text);
317  std::string token;
318  for (int i = 0; i < num_entry; ++i) {
319  std::getline(ss, token, ' ');
320  array.push_back(TextToNumber<T>(token));
321  }
322  return array;
323 }
324 
331 inline std::vector<std::string> Split(const std::string& text, char delim) {
332  std::vector<std::string> array;
333  std::istringstream ss(text);
334  std::string token;
335  while (std::getline(ss, token, delim)) {
336  array.push_back(token);
337  }
338  return array;
339 }
340 
341 } // namespace common
342 } // namespace treelite
343 #endif // TREELITE_COMMON_H_
std::vector< T > TextToArray(const std::string &text, int num_entry)
convert text to number array
Definition: common.h:314
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:196
std::string ToString(T value)
obtain a string representation of primitive type using ostringstream
Definition: common.h:164
abstract interface for classes that can be cloned
Definition: common.h:25
a wrapper around std::unique_ptr that supports deep copying and moving.
Definition: common.h:48
void WrapText(std::ostringstream *p_stm, size_t *p_length, const std::string &str, size_t indent, size_t textwidth)
insert a string into a string stream, adding a newline character ( ) so that the string stream has no...
Definition: common.h:124
std::vector< std::string > Split(const std::string &text, char delim)
split text using a delimiter
Definition: common.h:331
Iter binary_search(Iter begin, Iter end, const T &val)
perform binary search on the range [begin, end).
Definition: common.h:148
defines configuration macros of treelite
void WriteToFile(const std::string &filename, const std::string &content)
write a sequence of strings to a text file, with newline character ( ) inserted between strings...
Definition: common.h:180
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:91
T TextToNumber(const std::string &str)
convert text to number
Definition: common.h:210