field_view.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. //
  2. // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MYSQL_IMPL_FIELD_VIEW_HPP
  8. #define BOOST_MYSQL_IMPL_FIELD_VIEW_HPP
  9. #pragma once
  10. #include <boost/mysql/bad_field_access.hpp>
  11. #include <boost/mysql/blob.hpp>
  12. #include <boost/mysql/blob_view.hpp>
  13. #include <boost/mysql/field_kind.hpp>
  14. #include <boost/mysql/field_view.hpp>
  15. #include <boost/mysql/detail/auxiliar/access_fwd.hpp>
  16. #include <cstdio>
  17. #include <cstring>
  18. #include <limits>
  19. #include <ostream>
  20. namespace boost {
  21. namespace mysql {
  22. namespace detail {
  23. inline std::ostream& print_blob(std::ostream& os, blob_view value)
  24. {
  25. if (value.empty())
  26. return os << "{}";
  27. char buffer[16]{};
  28. os << "{ ";
  29. for (std::size_t i = 0; i < value.size(); ++i)
  30. {
  31. if (i != 0)
  32. os << ", ";
  33. unsigned byte = value[i];
  34. std::snprintf(buffer, sizeof(buffer), "0x%02x", byte);
  35. os << buffer;
  36. }
  37. os << " }";
  38. return os;
  39. }
  40. inline std::ostream& print_time(std::ostream& os, const time& value)
  41. {
  42. // Worst-case output is 26 chars, extra space just in case
  43. char buffer[64]{};
  44. using namespace std::chrono;
  45. const char* sign = value < microseconds(0) ? "-" : "";
  46. auto num_micros = value % seconds(1);
  47. auto num_secs = duration_cast<seconds>(value % minutes(1) - num_micros);
  48. auto num_mins = duration_cast<minutes>(value % hours(1) - num_secs);
  49. auto num_hours = duration_cast<hours>(value - num_mins);
  50. snprintf(
  51. buffer,
  52. sizeof(buffer),
  53. "%s%02d:%02u:%02u.%06u",
  54. sign,
  55. static_cast<int>(std::abs(num_hours.count())),
  56. static_cast<unsigned>(std::abs(num_mins.count())),
  57. static_cast<unsigned>(std::abs(num_secs.count())),
  58. static_cast<unsigned>(std::abs(num_micros.count()))
  59. );
  60. os << buffer;
  61. return os;
  62. }
  63. inline bool blobs_equal(blob_view b1, blob_view b2)
  64. {
  65. if (b1.size() != b2.size())
  66. return false;
  67. return b1.empty() || std::memcmp(b1.data(), b2.data(), b2.size()) == 0;
  68. }
  69. } // namespace detail
  70. } // namespace mysql
  71. } // namespace boost
  72. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(signed char v) noexcept
  73. : ikind_(internal_kind::int64), repr_(std::int64_t(v))
  74. {
  75. }
  76. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(short v) noexcept
  77. : ikind_(internal_kind::int64), repr_(std::int64_t(v))
  78. {
  79. }
  80. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(int v) noexcept
  81. : ikind_(internal_kind::int64), repr_(std::int64_t(v))
  82. {
  83. }
  84. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(long v) noexcept
  85. : ikind_(internal_kind::int64), repr_(std::int64_t(v))
  86. {
  87. }
  88. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(long long v) noexcept
  89. : ikind_(internal_kind::int64), repr_(std::int64_t(v))
  90. {
  91. }
  92. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(unsigned char v) noexcept
  93. : ikind_(internal_kind::uint64), repr_(std::uint64_t(v))
  94. {
  95. }
  96. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(unsigned short v) noexcept
  97. : ikind_(internal_kind::uint64), repr_(std::uint64_t(v))
  98. {
  99. }
  100. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(unsigned int v) noexcept
  101. : ikind_(internal_kind::uint64), repr_(std::uint64_t(v))
  102. {
  103. }
  104. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(unsigned long v) noexcept
  105. : ikind_(internal_kind::uint64), repr_(std::uint64_t(v))
  106. {
  107. }
  108. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(unsigned long long v) noexcept
  109. : ikind_(internal_kind::uint64), repr_(std::uint64_t(v))
  110. {
  111. }
  112. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(string_view v) noexcept
  113. : ikind_(internal_kind::string), repr_(v)
  114. {
  115. }
  116. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(blob_view v) noexcept
  117. : ikind_(internal_kind::blob), repr_(v)
  118. {
  119. }
  120. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(float v) noexcept
  121. : ikind_(internal_kind::float_), repr_(v)
  122. {
  123. }
  124. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(double v) noexcept
  125. : ikind_(internal_kind::double_), repr_(v)
  126. {
  127. }
  128. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(const date& v) noexcept
  129. : ikind_(internal_kind::date), repr_(v)
  130. {
  131. }
  132. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(const datetime& v) noexcept
  133. : ikind_(internal_kind::datetime), repr_(v)
  134. {
  135. }
  136. BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(const time& v) noexcept
  137. : ikind_(internal_kind::time), repr_(v)
  138. {
  139. }
  140. BOOST_CXX14_CONSTEXPR inline boost::mysql::field_kind boost::mysql::field_view::kind() const noexcept
  141. {
  142. switch (ikind_)
  143. {
  144. case internal_kind::null: return field_kind::null;
  145. case internal_kind::int64: return field_kind::int64;
  146. case internal_kind::uint64: return field_kind::uint64;
  147. case internal_kind::string: return field_kind::string;
  148. case internal_kind::blob: return field_kind::blob;
  149. case internal_kind::float_: return field_kind::float_;
  150. case internal_kind::double_: return field_kind::double_;
  151. case internal_kind::date: return field_kind::date;
  152. case internal_kind::datetime: return field_kind::datetime;
  153. case internal_kind::time: return field_kind::time;
  154. case internal_kind::field_ptr: return repr_.field_ptr->kind();
  155. // sv_offset values must be converted via offset_to_string_view before calling any other fn
  156. default: return field_kind::null;
  157. }
  158. }
  159. BOOST_CXX14_CONSTEXPR std::int64_t boost::mysql::field_view::as_int64() const
  160. {
  161. if (is_field_ptr())
  162. return repr_.field_ptr->as<std::int64_t>();
  163. check_kind(internal_kind::int64);
  164. return repr_.int64;
  165. }
  166. BOOST_CXX14_CONSTEXPR std::uint64_t boost::mysql::field_view::as_uint64() const
  167. {
  168. if (is_field_ptr())
  169. return repr_.field_ptr->as<std::uint64_t>();
  170. check_kind(internal_kind::uint64);
  171. return repr_.uint64;
  172. }
  173. BOOST_CXX14_CONSTEXPR boost::mysql::string_view boost::mysql::field_view::as_string() const
  174. {
  175. if (is_field_ptr())
  176. return repr_.field_ptr->as<std::string>();
  177. check_kind(internal_kind::string);
  178. return repr_.string;
  179. }
  180. BOOST_CXX14_CONSTEXPR boost::mysql::blob_view boost::mysql::field_view::as_blob() const
  181. {
  182. if (is_field_ptr())
  183. return repr_.field_ptr->as<blob>();
  184. check_kind(internal_kind::blob);
  185. return repr_.blob;
  186. }
  187. BOOST_CXX14_CONSTEXPR float boost::mysql::field_view::as_float() const
  188. {
  189. if (is_field_ptr())
  190. return repr_.field_ptr->as<float>();
  191. check_kind(internal_kind::float_);
  192. return repr_.float_;
  193. }
  194. BOOST_CXX14_CONSTEXPR double boost::mysql::field_view::as_double() const
  195. {
  196. if (is_field_ptr())
  197. return repr_.field_ptr->as<double>();
  198. check_kind(internal_kind::double_);
  199. return repr_.double_;
  200. }
  201. BOOST_CXX14_CONSTEXPR boost::mysql::date boost::mysql::field_view::as_date() const
  202. {
  203. if (is_field_ptr())
  204. return repr_.field_ptr->as<date>();
  205. check_kind(internal_kind::date);
  206. return repr_.date_;
  207. }
  208. BOOST_CXX14_CONSTEXPR boost::mysql::datetime boost::mysql::field_view::as_datetime() const
  209. {
  210. if (is_field_ptr())
  211. return repr_.field_ptr->as<datetime>();
  212. check_kind(internal_kind::datetime);
  213. return repr_.datetime_;
  214. }
  215. BOOST_CXX14_CONSTEXPR boost::mysql::time boost::mysql::field_view::as_time() const
  216. {
  217. if (is_field_ptr())
  218. return repr_.field_ptr->as<time>();
  219. check_kind(internal_kind::time);
  220. return repr_.time_;
  221. }
  222. BOOST_CXX14_CONSTEXPR std::int64_t boost::mysql::field_view::get_int64() const noexcept
  223. {
  224. return is_field_ptr() ? repr_.field_ptr->get<std::int64_t>() : repr_.int64;
  225. }
  226. BOOST_CXX14_CONSTEXPR std::uint64_t boost::mysql::field_view::get_uint64() const noexcept
  227. {
  228. return is_field_ptr() ? repr_.field_ptr->get<std::uint64_t>() : repr_.uint64;
  229. }
  230. BOOST_CXX14_CONSTEXPR boost::mysql::string_view boost::mysql::field_view::get_string() const noexcept
  231. {
  232. return is_field_ptr() ? string_view(repr_.field_ptr->get<std::string>()) : repr_.string;
  233. }
  234. BOOST_CXX14_CONSTEXPR boost::mysql::blob_view boost::mysql::field_view::get_blob() const noexcept
  235. {
  236. return is_field_ptr() ? repr_.field_ptr->get<blob>() : repr_.blob;
  237. }
  238. BOOST_CXX14_CONSTEXPR float boost::mysql::field_view::get_float() const noexcept
  239. {
  240. return is_field_ptr() ? repr_.field_ptr->get<float>() : repr_.float_;
  241. }
  242. BOOST_CXX14_CONSTEXPR double boost::mysql::field_view::get_double() const noexcept
  243. {
  244. return is_field_ptr() ? repr_.field_ptr->get<double>() : repr_.double_;
  245. }
  246. BOOST_CXX14_CONSTEXPR boost::mysql::date boost::mysql::field_view::get_date() const noexcept
  247. {
  248. return is_field_ptr() ? repr_.field_ptr->get<date>() : repr_.date_;
  249. }
  250. BOOST_CXX14_CONSTEXPR boost::mysql::datetime boost::mysql::field_view::get_datetime() const noexcept
  251. {
  252. return is_field_ptr() ? repr_.field_ptr->get<datetime>() : repr_.datetime_;
  253. }
  254. BOOST_CXX14_CONSTEXPR boost::mysql::time boost::mysql::field_view::get_time() const noexcept
  255. {
  256. return is_field_ptr() ? repr_.field_ptr->get<time>() : repr_.time_;
  257. }
  258. BOOST_CXX14_CONSTEXPR void boost::mysql::field_view::check_kind(internal_kind expected) const
  259. {
  260. if (ikind_ != expected)
  261. throw bad_field_access();
  262. }
  263. BOOST_CXX14_CONSTEXPR bool boost::mysql::field_view::operator==(const field_view& rhs) const noexcept
  264. {
  265. // Make operator== work for types not representable by field_kind
  266. if (ikind_ == internal_kind::sv_offset_string || ikind_ == internal_kind::sv_offset_blob)
  267. {
  268. return rhs.ikind_ == ikind_ && repr_.sv_offset_ == rhs.repr_.sv_offset_;
  269. }
  270. auto k = kind(), rhs_k = rhs.kind();
  271. switch (k)
  272. {
  273. case field_kind::null: return rhs_k == field_kind::null;
  274. case field_kind::int64:
  275. if (rhs_k == field_kind::int64)
  276. return get_int64() == rhs.get_int64();
  277. else if (rhs_k == field_kind::uint64)
  278. {
  279. std::int64_t this_val = get_int64();
  280. if (this_val < 0)
  281. return false;
  282. else
  283. return static_cast<std::uint64_t>(this_val) == rhs.get_uint64();
  284. }
  285. else
  286. return false;
  287. case field_kind::uint64:
  288. if (rhs_k == field_kind::uint64)
  289. return get_uint64() == rhs.get_uint64();
  290. else if (rhs_k == field_kind::int64)
  291. {
  292. std::int64_t rhs_val = rhs.get_int64();
  293. if (rhs_val < 0)
  294. return false;
  295. else
  296. return static_cast<std::uint64_t>(rhs_val) == get_uint64();
  297. }
  298. else
  299. return false;
  300. case field_kind::string: return rhs_k == field_kind::string && get_string() == rhs.get_string();
  301. case field_kind::blob:
  302. return rhs_k == field_kind::blob && detail::blobs_equal(get_blob(), rhs.get_blob());
  303. case field_kind::float_: return rhs_k == field_kind::float_ && get_float() == rhs.get_float();
  304. case field_kind::double_: return rhs_k == field_kind::double_ && get_double() == rhs.get_double();
  305. case field_kind::date: return rhs_k == field_kind::date && get_date() == rhs.get_date();
  306. case field_kind::datetime: return rhs_k == field_kind::datetime && get_datetime() == rhs.get_datetime();
  307. case field_kind::time: return rhs_k == field_kind::time && get_time() == rhs.get_time();
  308. default: assert(false); return false;
  309. }
  310. }
  311. inline std::ostream& boost::mysql::operator<<(std::ostream& os, const field_view& value)
  312. {
  313. // Make operator<< work for detail::string_view_offset types
  314. if (value.ikind_ == field_view::internal_kind::sv_offset_string ||
  315. value.ikind_ == field_view::internal_kind::sv_offset_blob)
  316. {
  317. return os << "<sv_offset>";
  318. }
  319. switch (value.kind())
  320. {
  321. case field_kind::null: return os << "<NULL>";
  322. case field_kind::int64: return os << value.get_int64();
  323. case field_kind::uint64: return os << value.get_uint64();
  324. case field_kind::string: return os << value.get_string();
  325. case field_kind::blob: return detail::print_blob(os, value.get_blob());
  326. case field_kind::float_: return os << value.get_float();
  327. case field_kind::double_: return os << value.get_double();
  328. case field_kind::date: return os << value.get_date();
  329. case field_kind::datetime: return os << value.get_datetime();
  330. case field_kind::time: return detail::print_time(os, value.get_time());
  331. default: assert(false); return os;
  332. }
  333. }
  334. struct boost::mysql::detail::field_view_access
  335. {
  336. static field_view construct(detail::string_view_offset v, bool is_blob) noexcept
  337. {
  338. return field_view(v, is_blob);
  339. }
  340. static void offset_to_string_view(field_view& fv, const std::uint8_t* buffer_first) noexcept
  341. {
  342. if (fv.ikind_ == field_view::internal_kind::sv_offset_string)
  343. {
  344. fv.ikind_ = field_view::internal_kind::string;
  345. fv.repr_.string = {
  346. reinterpret_cast<const char*>(buffer_first) + fv.repr_.sv_offset_.offset(),
  347. fv.repr_.sv_offset_.size()};
  348. }
  349. else if (fv.ikind_ == field_view::internal_kind::sv_offset_blob)
  350. {
  351. fv.ikind_ = field_view::internal_kind::blob;
  352. fv.repr_.blob = blob_view(
  353. buffer_first + fv.repr_.sv_offset_.offset(),
  354. fv.repr_.sv_offset_.size()
  355. );
  356. }
  357. }
  358. };
  359. #endif