strconv.hxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /** String conversion definitions.
  2. *
  3. * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stringconv instead.
  4. *
  5. * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
  6. *
  7. * See COPYING for copyright license. If you did not receive a file called
  8. * COPYING with this source code, please notify the distributor of this mistake,
  9. * or contact the author.
  10. */
  11. #ifndef PQXX_H_STRINGCONV
  12. #define PQXX_H_STRINGCONV
  13. #include "pqxx/compiler-public.hxx"
  14. #include <limits>
  15. #include <sstream>
  16. #include <stdexcept>
  17. namespace pqxx
  18. {
  19. /**
  20. * @defgroup stringconversion String conversion
  21. *
  22. * The PostgreSQL server accepts and represents data in string form. It has
  23. * its own formats for various data types. The string conversions define how
  24. * various C++ types translate to and from their respective PostgreSQL text
  25. * representations.
  26. *
  27. * Each conversion is defined by a specialisation of the @c string_traits
  28. * template. This template implements some basic functions to support the
  29. * conversion, ideally in both directions.
  30. *
  31. * If you need to convert a type which is not supported out of the box, define
  32. * your own @c string_traits specialisation for that type, similar to the ones
  33. * defined here. Any conversion code which "sees" your specialisation will now
  34. * support your conversion. In particular, you'll be able to read result
  35. * fields into a variable of the new type.
  36. *
  37. * There is a macro to help you define conversions for individual enumeration
  38. * types. The conversion will represent enumeration values as numeric strings.
  39. */
  40. //@{
  41. /// Traits class for use in string conversions
  42. /** Specialize this template for a type that you wish to add to_string and
  43. * from_string support for.
  44. */
  45. template<typename T, typename = void> struct string_traits;
  46. namespace internal
  47. {
  48. /// Throw exception for attempt to convert null to given type.
  49. [[noreturn]] PQXX_LIBEXPORT void throw_null_conversion(
  50. const std::string &type);
  51. /// Give a human-readable name for a type, at compile time.
  52. /** Each instantiation contains a static member called @c value which is the
  53. * type's name, as a string.
  54. *
  55. * This template should not be around for long. C++14's variable templates
  56. * make it easier (eliminating the cumbersome struct) and C++20's introspection
  57. * should obviate it completely.
  58. */
  59. template<typename TYPE> struct type_name;
  60. #define PQXX_DECLARE_TYPE_NAME(TYPE) \
  61. template<> struct type_name<TYPE> \
  62. { static constexpr const char *value = #TYPE; }
  63. PQXX_DECLARE_TYPE_NAME(bool);
  64. PQXX_DECLARE_TYPE_NAME(short);
  65. PQXX_DECLARE_TYPE_NAME(unsigned short);
  66. PQXX_DECLARE_TYPE_NAME(int);
  67. PQXX_DECLARE_TYPE_NAME(unsigned int);
  68. PQXX_DECLARE_TYPE_NAME(long);
  69. PQXX_DECLARE_TYPE_NAME(unsigned long);
  70. PQXX_DECLARE_TYPE_NAME(long long);
  71. PQXX_DECLARE_TYPE_NAME(unsigned long long);
  72. PQXX_DECLARE_TYPE_NAME(float);
  73. PQXX_DECLARE_TYPE_NAME(double);
  74. PQXX_DECLARE_TYPE_NAME(long double);
  75. PQXX_DECLARE_TYPE_NAME(char *);
  76. PQXX_DECLARE_TYPE_NAME(const char *);
  77. PQXX_DECLARE_TYPE_NAME(std::string);
  78. PQXX_DECLARE_TYPE_NAME(const std::string);
  79. PQXX_DECLARE_TYPE_NAME(std::stringstream);
  80. #undef PQXX_DECLARE_TYPE_NAME
  81. template<size_t N> struct type_name<char[N]>
  82. { static constexpr const char *value = "char[]"; };
  83. /// Helper: string traits implementation for built-in types.
  84. /** These types all look much alike, so they can share much of their traits
  85. * classes (though templatised, of course).
  86. *
  87. * The actual `to_string` and `from_string` are implemented in the library,
  88. * but the rest is defined inline.
  89. */
  90. template<typename TYPE> struct PQXX_LIBEXPORT builtin_traits
  91. {
  92. static constexpr const char *name() noexcept
  93. { return internal::type_name<TYPE>::value; }
  94. static constexpr bool has_null() noexcept { return false; }
  95. static bool is_null(TYPE) { return false; }
  96. [[noreturn]] static TYPE null() { throw_null_conversion(name()); }
  97. static void from_string(const char Str[], TYPE &Obj);
  98. static std::string to_string(TYPE Obj);
  99. };
  100. } // namespace pqxx::internal
  101. /// Helper: declare a string_traits specialisation for a builtin type.
  102. #define PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(TYPE) \
  103. template<> struct PQXX_LIBEXPORT string_traits<TYPE> : \
  104. internal::builtin_traits<TYPE> {};
  105. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(bool)
  106. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(short)
  107. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(unsigned short)
  108. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(int)
  109. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(unsigned int)
  110. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(long)
  111. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(unsigned long)
  112. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(long long)
  113. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(unsigned long long)
  114. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(float)
  115. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(double)
  116. PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION(long double)
  117. #undef PQXX_DECLARE_STRING_TRAITS_SPECIALIZATION
  118. /// Helper class for defining enum conversions.
  119. /** The conversion will convert enum values to numeric strings, and vice versa.
  120. *
  121. * To define a string conversion for an enum type, derive a @c string_traits
  122. * specialisation for the enum from this struct.
  123. *
  124. * There's usually an easier way though: the @c PQXX_DECLARE_ENUM_CONVERSION
  125. * macro. Use @c enum_traits manually only if you need to customise your
  126. * traits type in more detail, e.g. if your enum has a "null" value built in.
  127. */
  128. template<typename ENUM>
  129. struct enum_traits
  130. {
  131. using underlying_type = typename std::underlying_type<ENUM>::type;
  132. using underlying_traits = string_traits<underlying_type>;
  133. static constexpr bool has_null() noexcept { return false; }
  134. [[noreturn]] static ENUM null()
  135. { internal::throw_null_conversion("enum type"); }
  136. static void from_string(const char Str[], ENUM &Obj)
  137. {
  138. underlying_type tmp;
  139. underlying_traits::from_string(Str, tmp);
  140. Obj = ENUM(tmp);
  141. }
  142. static std::string to_string(ENUM Obj)
  143. { return underlying_traits::to_string(underlying_type(Obj)); }
  144. };
  145. /// Macro: Define a string conversion for an enum type.
  146. /** This specialises the @c pqxx::string_traits template, so use it in the
  147. * @c ::pqxx namespace.
  148. *
  149. * For example:
  150. *
  151. * #include <iostream>
  152. * #include <pqxx/strconv>
  153. * enum X { xa, xb };
  154. * namespace pqxx { PQXX_DECLARE_ENUM_CONVERSION(x); }
  155. * int main() { std::cout << to_string(xa) << std::endl; }
  156. */
  157. #define PQXX_DECLARE_ENUM_CONVERSION(ENUM) \
  158. template<> \
  159. struct string_traits<ENUM> : pqxx::enum_traits<ENUM> \
  160. { \
  161. static constexpr const char *name() noexcept { return #ENUM; } \
  162. [[noreturn]] static ENUM null() \
  163. { internal::throw_null_conversion(name()); } \
  164. }
  165. /// String traits for C-style string ("pointer to const char")
  166. template<> struct PQXX_LIBEXPORT string_traits<const char *>
  167. {
  168. static constexpr const char *name() noexcept { return "const char *"; }
  169. static constexpr bool has_null() noexcept { return true; }
  170. static bool is_null(const char *t) { return t == nullptr; }
  171. static const char *null() { return nullptr; }
  172. static void from_string(const char Str[], const char *&Obj) { Obj = Str; }
  173. static std::string to_string(const char *Obj) { return Obj; }
  174. };
  175. /// String traits for non-const C-style string ("pointer to char")
  176. template<> struct PQXX_LIBEXPORT string_traits<char *>
  177. {
  178. static constexpr const char *name() noexcept { return "char *"; }
  179. static constexpr bool has_null() noexcept { return true; }
  180. static bool is_null(const char *t) { return t == nullptr; }
  181. static const char *null() { return nullptr; }
  182. // Don't allow this conversion since it breaks const-safety.
  183. // static void from_string(const char Str[], char *&Obj);
  184. static std::string to_string(char *Obj) { return Obj; }
  185. };
  186. /// String traits for C-style string constant ("array of char")
  187. template<size_t N> struct PQXX_LIBEXPORT string_traits<char[N]>
  188. {
  189. static constexpr const char *name() noexcept { return "char[]"; }
  190. static constexpr bool has_null() noexcept { return true; }
  191. static bool is_null(const char t[]) { return t == nullptr; }
  192. static const char *null() { return nullptr; }
  193. static std::string to_string(const char Obj[]) { return Obj; }
  194. };
  195. template<> struct PQXX_LIBEXPORT string_traits<std::string>
  196. {
  197. static constexpr const char *name() noexcept { return "string"; }
  198. static constexpr bool has_null() noexcept { return false; }
  199. static bool is_null(const std::string &) { return false; }
  200. [[noreturn]] static std::string null()
  201. { internal::throw_null_conversion(name()); }
  202. static void from_string(const char Str[], std::string &Obj) { Obj=Str; }
  203. static std::string to_string(const std::string &Obj) { return Obj; }
  204. };
  205. template<> struct PQXX_LIBEXPORT string_traits<const std::string>
  206. {
  207. static constexpr const char *name() noexcept { return "const string"; }
  208. static constexpr bool has_null() noexcept { return false; }
  209. static bool is_null(const std::string &) { return false; }
  210. [[noreturn]] static const std::string null()
  211. { internal::throw_null_conversion(name()); }
  212. static const std::string to_string(const std::string &Obj) { return Obj; }
  213. };
  214. template<> struct PQXX_LIBEXPORT string_traits<std::stringstream>
  215. {
  216. static constexpr const char *name() noexcept { return "stringstream"; }
  217. static constexpr bool has_null() noexcept { return false; }
  218. static bool is_null(const std::stringstream &) { return false; }
  219. [[noreturn]] static std::stringstream null()
  220. { internal::throw_null_conversion(name()); }
  221. static void from_string(const char Str[], std::stringstream &Obj)
  222. { Obj.clear(); Obj << Str; }
  223. static std::string to_string(const std::stringstream &Obj)
  224. { return Obj.str(); }
  225. };
  226. // TODO: Implement date conversions.
  227. /// Attempt to convert postgres-generated string to given built-in type
  228. /** If the form of the value found in the string does not match the expected
  229. * type, e.g. if a decimal point is found when converting to an integer type,
  230. * the conversion fails. Overflows (e.g. converting "9999999999" to a 16-bit
  231. * C++ type) are also treated as errors. If in some cases this behaviour should
  232. * be inappropriate, convert to something bigger such as @c long @c int first
  233. * and then truncate the resulting value.
  234. *
  235. * Only the simplest possible conversions are supported. No fancy features
  236. * such as hexadecimal or octal, spurious signs, or exponent notation will work.
  237. * No whitespace is stripped away. Only the kinds of strings that come out of
  238. * PostgreSQL and out of to_string() can be converted.
  239. */
  240. template<typename T>
  241. inline void from_string(const char Str[], T &Obj)
  242. {
  243. if (Str == nullptr) throw std::runtime_error{"Attempt to read null string."};
  244. string_traits<T>::from_string(Str, Obj);
  245. }
  246. /// Conversion with known string length (for strings that may contain nuls)
  247. /** This is only used for strings, where embedded nul bytes should not determine
  248. * the end of the string.
  249. *
  250. * For all other types, this just uses the regular, nul-terminated version of
  251. * from_string().
  252. */
  253. template<typename T> inline void from_string(const char Str[], T &Obj, size_t)
  254. {
  255. return from_string(Str, Obj);
  256. }
  257. template<>
  258. inline void from_string<std::string>( //[t00]
  259. const char Str[],
  260. std::string &Obj,
  261. size_t len)
  262. {
  263. if (Str == nullptr) throw std::runtime_error{"Attempt to read null string."};
  264. Obj.assign(Str, len);
  265. }
  266. template<typename T>
  267. inline void from_string(const std::string &Str, T &Obj) //[t45]
  268. { from_string(Str.c_str(), Obj); }
  269. template<typename T>
  270. inline void from_string(const std::stringstream &Str, T &Obj) //[t00]
  271. { from_string(Str.str(), Obj); }
  272. template<> inline void
  273. from_string(const std::string &Str, std::string &Obj) //[t46]
  274. { Obj = Str; }
  275. namespace internal
  276. {
  277. /// Compute numeric value of given textual digit (assuming that it is a digit)
  278. constexpr int digit_to_number(char c) noexcept { return c-'0'; }
  279. constexpr char number_to_digit(int i) noexcept
  280. { return static_cast<char>(i+'0'); }
  281. } // namespace pqxx::internal
  282. /// Convert built-in type to a readable string that PostgreSQL will understand
  283. /** No special formatting is done, and any locale settings are ignored. The
  284. * resulting string will be human-readable and in a format suitable for use in
  285. * SQL queries.
  286. */
  287. template<typename T> inline std::string to_string(const T &Obj)
  288. { return string_traits<T>::to_string(Obj); }
  289. //@}
  290. } // namespace pqxx
  291. #endif