util.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License, version 2.0, as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is also distributed with certain software (including
  9. * but not limited to OpenSSL) that is licensed under separate terms,
  10. * as designated in a particular file or component or in included license
  11. * documentation. The authors of MySQL hereby grant you an
  12. * additional permission to link the program and your derivative works
  13. * with the separately licensed software that they have included with
  14. * MySQL.
  15. *
  16. * Without limiting anything contained in the foregoing, this file,
  17. * which is part of MySQL Connector/C++, is also subject to the
  18. * Universal FOSS Exception, version 1.0, a copy of which can be found at
  19. * http://oss.oracle.com/licenses/universal-foss-exception.
  20. *
  21. * This program is distributed in the hope that it will be useful, but
  22. * WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  24. * See the GNU General Public License, version 2.0, for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software Foundation, Inc.,
  28. * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  29. */
  30. #ifndef MYSQLX_COMMON_UTIL_H
  31. #define MYSQLX_COMMON_UTIL_H
  32. #include <string>
  33. #include <stdexcept>
  34. #include <ostream>
  35. #include <memory>
  36. #include <forward_list>
  37. #include <string.h> // for memcpy
  38. #include <utility> // std::move etc
  39. #include <algorithm>
  40. #include <functional>
  41. #include <type_traits>
  42. /*
  43. Macro to be used to disable "implicit fallthrough" gcc warning
  44. <https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html>
  45. */
  46. #ifndef FALLTHROUGH
  47. # ifdef __GNUC__
  48. # if __GNUC__ < 7
  49. # define FALLTHROUGH // fallthrough
  50. # else
  51. # if __cplusplus >= 201703L
  52. # define FALLTHROUGH [[fallthrough]] // C++17
  53. # elif __cplusplus >= 201103L
  54. # define FALLTHROUGH [[gnu::fallthrough]] // C++11 and C++14
  55. # else
  56. # define FALLTHROUGH __attribute__((fallthrough))
  57. # endif
  58. # endif
  59. # else
  60. # define FALLTHROUGH // fallthrough
  61. # endif
  62. #endif //FALLTHROUGH
  63. /*
  64. Note: we add throw statement to the definition of THROW() so that compiler won't
  65. complain if it is used in contexts where, e.g., a value should be returned from
  66. a function.
  67. */
  68. #undef THROW
  69. #ifdef THROW_AS_ASSERT
  70. #define THROW(MSG) do { assert(false && (MSG)); throw (MSG); } while(false)
  71. #else
  72. #define THROW(MSG) do { throw_error(MSG); throw (MSG); } while(false)
  73. #endif
  74. /*
  75. Macros used to disable warnings for fragments of code.
  76. */
  77. #undef PRAGMA
  78. #undef DISABLE_WARNING
  79. #undef DIAGNOSTIC_PUSH
  80. #undef DIAGNOSTIC_POP
  81. #if defined __GNUC__ || defined __clang__
  82. #define PRAGMA(X) _Pragma(#X)
  83. #define DISABLE_WARNING(W) PRAGMA(GCC diagnostic ignored #W)
  84. #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
  85. #define DIAGNOSTIC_PUSH PRAGMA(GCC diagnostic push)
  86. #define DIAGNOSTIC_POP PRAGMA(GCC diagnostic pop)
  87. #else
  88. #define DIAGNOSTIC_PUSH
  89. #define DIAGNOSTIC_POP
  90. #endif
  91. #elif defined _MSC_VER
  92. #define PRAGMA(X) __pragma(X)
  93. #define DISABLE_WARNING(W) PRAGMA(warning (disable:W))
  94. #define DIAGNOSTIC_PUSH PRAGMA(warning (push))
  95. #define DIAGNOSTIC_POP PRAGMA(warning (pop))
  96. #else
  97. #define PRAGMA(X)
  98. #define DISABLE_WARNING(W)
  99. #define DIAGNOSTIC_PUSH
  100. #define DIAGNOSTIC_POP
  101. #endif
  102. /*
  103. On Windows, MSVC issues warnings if public API class definition uses
  104. another class which is not exported as public API (either as a base class
  105. or type of member). This is indeed dangerous because client code might get
  106. the class definition wrong if the non-exported component is not available or
  107. (worse) is defined in a different way than the same component during connector
  108. build time.
  109. We can not completely avoid these warnings because for some API classes we
  110. use standard C++ library classes as components. For example, we use
  111. std::shared_ptr<> a lot. We can not modify standard library headers to export
  112. these classes. As is the common practice, we ignore this issue assuming that
  113. the code that uses our connector is built with the same C++ runtime
  114. implementation as the one used to build the connector. To silence the warnings,
  115. uses of standard library classes in our public API classes should be surrounded
  116. with DLL_WARNINGS_PUSH/POP macros.
  117. */
  118. #if defined _MSC_VER
  119. #define DLL_WARNINGS_PUSH DIAGNOSTIC_PUSH \
  120. DISABLE_WARNING(4251) \
  121. DISABLE_WARNING(4275)
  122. #define DLL_WARNINGS_POP DIAGNOSTIC_POP
  123. #else
  124. #define DLL_WARNINGS_PUSH
  125. #define DLL_WARNINGS_POP
  126. #endif
  127. /*
  128. A dirty trick to help Doxygen to process 'enum class' declarations, which
  129. are not fully supported. Thus we replace them by plain 'enum' when processing
  130. sources by Doxygen.
  131. */
  132. #ifdef DOXYGEN
  133. #define enum_class enum
  134. #else
  135. #define enum_class enum class
  136. #endif
  137. /*
  138. Macro to put at the end of other macros that define lists of items. This is
  139. another dirty trick for Doxygen to hide from it a documentation of the last
  140. item in the list. Otherwise, in a situation like this:
  141. #define ITEM_LIST(X) \
  142. X(item1) \
  143. ...
  144. X(itemN) /##< Doc for last item #/
  145. Doxegen treats the documentation of the last item as documentation for
  146. the whole ITEM_LIST() macro. This does not happen if END_LIST is added at
  147. the end:
  148. #define ITEM_LIST(X) \
  149. X(item1) \
  150. ...
  151. X(itemN) /##< Doc for last item #/ \
  152. END_LIST
  153. */
  154. #define END_LIST
  155. namespace mysqlx {
  156. namespace common {
  157. /*
  158. Convenience for checking numeric limits (to be used when doing numeric
  159. casts).
  160. TODO: Maybe more templates are needed for the case where T is a float/double
  161. type and U is an integer type or vice versa.
  162. */
  163. #ifdef __cplusplus
  164. template <
  165. typename T, typename U,
  166. typename std::enable_if<std::is_unsigned<U>::value>::type* = nullptr
  167. >
  168. inline
  169. bool check_num_limits(U val)
  170. {
  171. using UT = typename std::make_unsigned<T>::type;
  172. return !(val > (UT)std::numeric_limits<T>::max());
  173. }
  174. template <
  175. typename T, typename U,
  176. typename std::enable_if<std::is_unsigned<T>::value>::type* = nullptr,
  177. typename std::enable_if<!std::is_unsigned<U>::value>::type* = nullptr
  178. >
  179. inline
  180. bool check_num_limits(U val)
  181. {
  182. return !(val < 0) && !(val > std::numeric_limits<T>::max());
  183. }
  184. template <
  185. typename T, typename U,
  186. typename std::enable_if<!std::is_unsigned<T>::value>::type* = nullptr,
  187. typename std::enable_if<!std::is_unsigned<U>::value>::type* = nullptr
  188. >
  189. inline
  190. bool check_num_limits(U val)
  191. {
  192. return
  193. !((val > std::numeric_limits<T>::max())
  194. || (val < std::numeric_limits<T>::lowest()));
  195. }
  196. #define ASSERT_NUM_LIMITS(T,V) assert(mysqlx::common::check_num_limits<T>(V))
  197. #endif
  198. inline
  199. std::string to_upper(const std::string &val)
  200. {
  201. using std::transform;
  202. std::string uc_val;
  203. uc_val.resize(val.size());
  204. transform(val.begin(), val.end(), uc_val.begin(), ::toupper);
  205. return std::move(uc_val);
  206. }
  207. inline
  208. std::string to_lower(const std::string &val)
  209. {
  210. using std::transform;
  211. std::string uc_val;
  212. uc_val.resize(val.size());
  213. transform(val.begin(), val.end(), uc_val.begin(), ::tolower);
  214. return std::move(uc_val);
  215. }
  216. } // common
  217. namespace common {
  218. #ifdef USE_NATIVE_BYTE
  219. using ::byte;
  220. #else
  221. typedef unsigned char byte;
  222. #endif
  223. class nocopy
  224. {
  225. public:
  226. nocopy(const nocopy&) = delete;
  227. nocopy& operator=(const nocopy&) = delete;
  228. protected:
  229. nocopy() {}
  230. };
  231. class Printable
  232. {
  233. virtual void print(std::ostream&) const = 0;
  234. friend std::ostream& operator<<(std::ostream&, const Printable&);
  235. };
  236. inline
  237. std::ostream& operator<<(std::ostream &out, const Printable &obj)
  238. {
  239. obj.print(out);
  240. return out;
  241. }
  242. } // common
  243. namespace common {
  244. using std::find_if;
  245. /*
  246. Remove from a container all elements that satisfy the given predicate.
  247. */
  248. template <class CONT, class PRED>
  249. void remove_from(CONT &cont, PRED pred)
  250. {
  251. using It = typename CONT::iterator;
  252. It end = std::remove_if(cont.begin(), cont.end(), pred);
  253. cont.erase(end, cont.end());
  254. }
  255. } // common
  256. } // mysqlx
  257. #endif