/primitiv/msgpack/writer.h

https://github.com/primitiv/primitiv · C Header · 491 lines · 455 code · 29 blank · 7 comment · 65 complexity · b27e92d203389cf8a8570436f04e2e13 MD5 · raw file

  1. #ifndef PRIMITIV_MSGPACK_WRITER_H_
  2. #define PRIMITIV_MSGPACK_WRITER_H_
  3. #include <primitiv/config.h>
  4. #include <cstddef>
  5. #include <cstdint>
  6. #include <cstring>
  7. #include <ostream>
  8. #include <string>
  9. #include <vector>
  10. #include <unordered_map>
  11. #include <primitiv/core/error.h>
  12. #include <primitiv/core/mixins/nonmovable.h>
  13. #include <primitiv/msgpack/objects.h>
  14. namespace primitiv {
  15. namespace msgpack {
  16. #define PRIMITIV_UC(expr) static_cast<char>(expr)
  17. /**
  18. * ostream-like MessagePack writer.
  19. */
  20. class Writer : mixins::Nonmovable<Writer> {
  21. std::ostream &os_;
  22. private:
  23. Writer &write_string(const char *x, std::size_t size) {
  24. #ifdef PRIMITIV_WORDSIZE_64
  25. static_assert(sizeof(std::size_t) > sizeof(std::uint32_t), "");
  26. if (size < (1 << 5)) {
  27. const char buf[1] { PRIMITIV_UC(0xa0 | (size & 0x1f)) };
  28. os_.write(buf, 1);
  29. } else if (size < (1ull << 8)) {
  30. const char buf[2] { PRIMITIV_UC(0xd9), PRIMITIV_UC(size) };
  31. os_.write(buf, 2);
  32. } else if (size < (1ull << 16)) {
  33. const char buf[3] {
  34. PRIMITIV_UC(0xda), PRIMITIV_UC(size >> 8), PRIMITIV_UC(size)
  35. };
  36. os_.write(buf, 3);
  37. } else if (size < (1ull << 32)) {
  38. const char buf[5] {
  39. PRIMITIV_UC(0xdb),
  40. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  41. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  42. };
  43. os_.write(buf, 5);
  44. } else {
  45. PRIMITIV_THROW_ERROR(
  46. "MessagePack: Can't store more than 2^32 - 1 bytes "
  47. "in one str message.");
  48. }
  49. os_.write(x, size);
  50. return *this;
  51. #else
  52. static_assert(sizeof(std::size_t) == sizeof(std::uint32_t), "");
  53. if (size < (1 << 5)) {
  54. const char buf[1] { PRIMITIV_UC(0xa0 | (size & 0x1f)) };
  55. os_.write(buf, 1);
  56. } else if (size < (1ul << 8)) {
  57. const char buf[2] { PRIMITIV_UC(0xd9), PRIMITIV_UC(size) };
  58. os_.write(buf, 2);
  59. } else if (size < (1ul << 16)) {
  60. const char buf[3] {
  61. PRIMITIV_UC(0xda), PRIMITIV_UC(size >> 8), PRIMITIV_UC(size)
  62. };
  63. os_.write(buf, 3);
  64. } else {
  65. const char buf[5] {
  66. PRIMITIV_UC(0xdb),
  67. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  68. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  69. };
  70. os_.write(buf, 5);
  71. }
  72. os_.write(x, size);
  73. return *this;
  74. #endif
  75. }
  76. public:
  77. /**
  78. * Creates a new Writer object.
  79. * @param os Target output stream.
  80. */
  81. Writer(std::ostream &os) : os_(os) {}
  82. Writer &operator<<(std::nullptr_t) {
  83. const char buf[1] { PRIMITIV_UC(0xc0) };
  84. os_.write(buf, 1);
  85. return *this;
  86. }
  87. Writer &operator<<(bool x) {
  88. const char buf[2] { PRIMITIV_UC(0xc2), PRIMITIV_UC(0xc3) };
  89. os_.write(&buf[!!x], 1);
  90. return *this;
  91. }
  92. Writer &operator<<(std::uint8_t x) {
  93. const char buf[2] { PRIMITIV_UC(0xcc), PRIMITIV_UC(x) };
  94. os_.write(buf, 2);
  95. return *this;
  96. }
  97. Writer &operator<<(std::uint16_t x) {
  98. const char buf[3] {
  99. PRIMITIV_UC(0xcd), PRIMITIV_UC(x >> 8), PRIMITIV_UC(x)
  100. };
  101. os_.write(buf, 3);
  102. return *this;
  103. }
  104. Writer &operator<<(std::uint32_t x) {
  105. const char buf[5] {
  106. PRIMITIV_UC(0xce),
  107. PRIMITIV_UC(x >> 24), PRIMITIV_UC(x >> 16),
  108. PRIMITIV_UC(x >> 8), PRIMITIV_UC(x),
  109. };
  110. os_.write(buf, 5);
  111. return *this;
  112. }
  113. Writer &operator<<(std::uint64_t x) {
  114. const char buf[9] {
  115. PRIMITIV_UC(0xcf),
  116. PRIMITIV_UC(x >> 56), PRIMITIV_UC(x >> 48),
  117. PRIMITIV_UC(x >> 40), PRIMITIV_UC(x >> 32),
  118. PRIMITIV_UC(x >> 24), PRIMITIV_UC(x >> 16),
  119. PRIMITIV_UC(x >> 8), PRIMITIV_UC(x),
  120. };
  121. os_.write(buf, 9);
  122. return *this;
  123. }
  124. Writer &operator<<(std::int8_t x) {
  125. const char buf[2] { PRIMITIV_UC(0xd0), PRIMITIV_UC(x) };
  126. os_.write(buf, 2);
  127. return *this;
  128. }
  129. Writer &operator<<(std::int16_t x) {
  130. const char buf[3] {
  131. PRIMITIV_UC(0xd1), PRIMITIV_UC(x >> 8), PRIMITIV_UC(x)
  132. };
  133. os_.write(buf, 3);
  134. return *this;
  135. }
  136. Writer &operator<<(std::int32_t x) {
  137. const char buf[5] {
  138. PRIMITIV_UC(0xd2),
  139. PRIMITIV_UC(x >> 24), PRIMITIV_UC(x >> 16),
  140. PRIMITIV_UC(x >> 8), PRIMITIV_UC(x),
  141. };
  142. os_.write(buf, 5);
  143. return *this;
  144. }
  145. Writer &operator<<(std::int64_t x) {
  146. const char buf[9] {
  147. PRIMITIV_UC(0xd3),
  148. PRIMITIV_UC(x >> 56), PRIMITIV_UC(x >> 48),
  149. PRIMITIV_UC(x >> 40), PRIMITIV_UC(x >> 32),
  150. PRIMITIV_UC(x >> 24), PRIMITIV_UC(x >> 16),
  151. PRIMITIV_UC(x >> 8), PRIMITIV_UC(x),
  152. };
  153. os_.write(buf, 9);
  154. return *this;
  155. }
  156. Writer &operator<<(float x) {
  157. static_assert(sizeof(float) == sizeof(std::uint32_t), "");
  158. std::uint32_t y;
  159. std::memcpy(&y, &x, sizeof(float));
  160. const char buf[5] {
  161. PRIMITIV_UC(0xca),
  162. PRIMITIV_UC(y >> 24), PRIMITIV_UC(y >> 16),
  163. PRIMITIV_UC(y >> 8), PRIMITIV_UC(y),
  164. };
  165. os_.write(buf, 5);
  166. return *this;
  167. }
  168. Writer &operator<<(double x) {
  169. static_assert(sizeof(double) == sizeof(std::uint64_t), "");
  170. std::uint64_t y;
  171. std::memcpy(&y, &x, sizeof(double));
  172. const char buf[9] {
  173. PRIMITIV_UC(0xcb),
  174. PRIMITIV_UC(y >> 56), PRIMITIV_UC(y >> 48),
  175. PRIMITIV_UC(y >> 40), PRIMITIV_UC(y >> 32),
  176. PRIMITIV_UC(y >> 24), PRIMITIV_UC(y >> 16),
  177. PRIMITIV_UC(y >> 8), PRIMITIV_UC(y),
  178. };
  179. os_.write(buf, 9);
  180. return *this;
  181. }
  182. Writer &operator<<(const char *x) {
  183. return write_string(x, std::strlen(x));
  184. }
  185. Writer &operator<<(const std::string &x) {
  186. return write_string(x.data(), x.size());
  187. }
  188. Writer &operator<<(const objects::Binary &x) {
  189. #ifdef PRIMITIV_WORDSIZE_64
  190. static_assert(sizeof(std::size_t) > sizeof(std::uint32_t), "");
  191. const std::size_t size = x.size();
  192. if (size < (1ull << 8)) {
  193. const char buf[2] { PRIMITIV_UC(0xc4), PRIMITIV_UC(size) };
  194. os_.write(buf, 2);
  195. } else if (size < (1ull << 16)) {
  196. const char buf[3] {
  197. PRIMITIV_UC(0xc5), PRIMITIV_UC(size >> 8), PRIMITIV_UC(size)
  198. };
  199. os_.write(buf, 3);
  200. } else if (size < (1ull << 32)) {
  201. const char buf[5] {
  202. PRIMITIV_UC(0xc6),
  203. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  204. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  205. };
  206. os_.write(buf, 5);
  207. } else {
  208. PRIMITIV_THROW_ERROR(
  209. "MessagePack: Can't store more than 2^32 - 1 bytes "
  210. "in one bin message.");
  211. }
  212. os_.write(reinterpret_cast<const char *>(x.data()), size);
  213. return *this;
  214. #else
  215. static_assert(sizeof(std::size_t) == sizeof(std::uint32_t), "");
  216. const std::size_t size = x.size();
  217. if (size < (1ul << 8)) {
  218. const char buf[2] { PRIMITIV_UC(0xc4), PRIMITIV_UC(size) };
  219. os_.write(buf, 2);
  220. } else if (size < (1ul << 16)) {
  221. const char buf[3] {
  222. PRIMITIV_UC(0xc5), PRIMITIV_UC(size >> 8), PRIMITIV_UC(size)
  223. };
  224. os_.write(buf, 3);
  225. } else {
  226. const char buf[5] {
  227. PRIMITIV_UC(0xc6),
  228. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  229. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  230. };
  231. os_.write(buf, 5);
  232. }
  233. os_.write(reinterpret_cast<const char *>(x.data()), size);
  234. return *this;
  235. #endif
  236. }
  237. Writer &operator<<(const objects::Extension &x) {
  238. #ifdef PRIMITIV_WORDSIZE_64
  239. static_assert(sizeof(std::size_t) > sizeof(std::uint32_t), "");
  240. const std::int8_t type = x.type();
  241. const std::size_t size = x.size();
  242. if (size < (1ull << 8)) {
  243. switch (size) {
  244. case 1:
  245. {
  246. const char buf[2] { PRIMITIV_UC(0xd4), PRIMITIV_UC(type) };
  247. os_.write(buf, 2);
  248. break;
  249. }
  250. case 2:
  251. {
  252. const char buf[2] { PRIMITIV_UC(0xd5), PRIMITIV_UC(type) };
  253. os_.write(buf, 2);
  254. break;
  255. }
  256. case 4:
  257. {
  258. const char buf[2] { PRIMITIV_UC(0xd6), PRIMITIV_UC(type) };
  259. os_.write(buf, 2);
  260. break;
  261. }
  262. case 8:
  263. {
  264. const char buf[2] { PRIMITIV_UC(0xd7), PRIMITIV_UC(type) };
  265. os_.write(buf, 2);
  266. break;
  267. }
  268. case 16:
  269. {
  270. const char buf[2] { PRIMITIV_UC(0xd8), PRIMITIV_UC(type) };
  271. os_.write(buf, 2);
  272. break;
  273. }
  274. default:
  275. {
  276. const char buf[3] {
  277. PRIMITIV_UC(0xc7), PRIMITIV_UC(size), PRIMITIV_UC(type)
  278. };
  279. os_.write(buf, 3);
  280. }
  281. }
  282. } else if (size < (1ull << 16)) {
  283. const char buf[4] {
  284. PRIMITIV_UC(0xc8), PRIMITIV_UC(size >> 8),
  285. PRIMITIV_UC(size), PRIMITIV_UC(type)
  286. };
  287. os_.write(buf, 4);
  288. } else if (size < (1ull << 32)) {
  289. const char buf[6] {
  290. PRIMITIV_UC(0xc9),
  291. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  292. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  293. PRIMITIV_UC(type),
  294. };
  295. os_.write(buf, 6);
  296. } else {
  297. PRIMITIV_THROW_ERROR(
  298. "MessagePack: Can't store more than 2^32 - 1 bytes "
  299. "in one ext message.");
  300. }
  301. os_.write(reinterpret_cast<const char *>(x.data()), size);
  302. return *this;
  303. #else
  304. static_assert(sizeof(std::size_t) == sizeof(std::uint32_t), "");
  305. const std::int8_t type = x.type();
  306. const std::size_t size = x.size();
  307. if (size < (1ul << 8)) {
  308. switch (size) {
  309. case 1:
  310. {
  311. const char buf[2] { PRIMITIV_UC(0xd4), PRIMITIV_UC(type) };
  312. os_.write(buf, 2);
  313. break;
  314. }
  315. case 2:
  316. {
  317. const char buf[2] { PRIMITIV_UC(0xd5), PRIMITIV_UC(type) };
  318. os_.write(buf, 2);
  319. break;
  320. }
  321. case 4:
  322. {
  323. const char buf[2] { PRIMITIV_UC(0xd6), PRIMITIV_UC(type) };
  324. os_.write(buf, 2);
  325. break;
  326. }
  327. case 8:
  328. {
  329. const char buf[2] { PRIMITIV_UC(0xd7), PRIMITIV_UC(type) };
  330. os_.write(buf, 2);
  331. break;
  332. }
  333. case 16:
  334. {
  335. const char buf[2] { PRIMITIV_UC(0xd8), PRIMITIV_UC(type) };
  336. os_.write(buf, 2);
  337. break;
  338. }
  339. default:
  340. {
  341. const char buf[3] {
  342. PRIMITIV_UC(0xc7), PRIMITIV_UC(size), PRIMITIV_UC(type)
  343. };
  344. os_.write(buf, 3);
  345. }
  346. }
  347. } else if (size < (1ul << 16)) {
  348. const char buf[4] {
  349. PRIMITIV_UC(0xc8), PRIMITIV_UC(size >> 8),
  350. PRIMITIV_UC(size), PRIMITIV_UC(type)
  351. };
  352. os_.write(buf, 4);
  353. } else {
  354. const char buf[6] {
  355. PRIMITIV_UC(0xc9),
  356. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  357. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  358. PRIMITIV_UC(type),
  359. };
  360. os_.write(buf, 6);
  361. }
  362. os_.write(reinterpret_cast<const char *>(x.data()), size);
  363. return *this;
  364. #endif
  365. }
  366. template<typename T>
  367. Writer &operator<<(const std::vector<T> &x) {
  368. #ifdef PRIMITIV_WORDSIZE_64
  369. static_assert(sizeof(std::size_t) > sizeof(std::uint32_t), "");
  370. const std::size_t size = x.size();
  371. if (size < (1ull << 4)) {
  372. const char buf[1] { PRIMITIV_UC(0x90 | (size & 0x0f)) };
  373. os_.write(buf, 1);
  374. } else if (size < (1ull << 16)) {
  375. const char buf[3] {
  376. PRIMITIV_UC(0xdc), PRIMITIV_UC(size >> 8), PRIMITIV_UC(size)
  377. };
  378. os_.write(buf, 3);
  379. } else if (size < (1ull << 32)) {
  380. const char buf[5] {
  381. PRIMITIV_UC(0xdd),
  382. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  383. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  384. };
  385. os_.write(buf, 5);
  386. }
  387. for (const T &elm : x) *this << elm;
  388. return *this;
  389. #else
  390. static_assert(sizeof(std::size_t) == sizeof(std::uint32_t), "");
  391. const std::size_t size = x.size();
  392. if (size < (1ul << 4)) {
  393. const char buf[1] { PRIMITIV_UC(0x90 | (size & 0x0f)) };
  394. os_.write(buf, 1);
  395. } else if (size < (1ul << 16)) {
  396. const char buf[3] {
  397. PRIMITIV_UC(0xdc), PRIMITIV_UC(size >> 8), PRIMITIV_UC(size)
  398. };
  399. os_.write(buf, 3);
  400. } else {
  401. const char buf[5] {
  402. PRIMITIV_UC(0xdd),
  403. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  404. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  405. };
  406. os_.write(buf, 5);
  407. }
  408. for (const T &elm : x) *this << elm;
  409. return *this;
  410. #endif
  411. }
  412. template<typename T, typename U>
  413. Writer &operator<<(const std::unordered_map<T, U> &x) {
  414. #ifdef PRIMITIV_WORDSIZE_64
  415. static_assert(sizeof(std::size_t) > sizeof(std::uint32_t), "");
  416. const std::size_t size = x.size();
  417. if (size < (1ull << 4)) {
  418. const char buf[1] { PRIMITIV_UC(0x80 | (size & 0x0f)) };
  419. os_.write(buf, 1);
  420. } else if (size < (1ull << 16)) {
  421. const char buf[3] {
  422. PRIMITIV_UC(0xde), PRIMITIV_UC(size >> 8), PRIMITIV_UC(size)
  423. };
  424. os_.write(buf, 3);
  425. } else if (size < (1ull << 32)) {
  426. const char buf[5] {
  427. PRIMITIV_UC(0xdf),
  428. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  429. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  430. };
  431. os_.write(buf, 5);
  432. }
  433. for (const std::pair<T, U> &elm : x) *this << elm.first << elm.second;
  434. return *this;
  435. #else
  436. static_assert(sizeof(std::size_t) == sizeof(std::uint32_t), "");
  437. const std::size_t size = x.size();
  438. if (size < (1ul << 4)) {
  439. const char buf[1] { PRIMITIV_UC(0x80 | (size & 0x0f)) };
  440. os_.write(buf, 1);
  441. } else if (size < (1ul << 16)) {
  442. const char buf[3] {
  443. PRIMITIV_UC(0xde), PRIMITIV_UC(size >> 8), PRIMITIV_UC(size)
  444. };
  445. os_.write(buf, 3);
  446. } else {
  447. const char buf[5] {
  448. PRIMITIV_UC(0xdf),
  449. PRIMITIV_UC(size >> 24), PRIMITIV_UC(size >> 16),
  450. PRIMITIV_UC(size >> 8), PRIMITIV_UC(size),
  451. };
  452. os_.write(buf, 5);
  453. }
  454. for (const std::pair<T, U> &elm : x) *this << elm.first << elm.second;
  455. return *this;
  456. #endif
  457. }
  458. };
  459. #undef PRIMITIV_UC
  460. } // namespace msgpack
  461. } // namespace primitiv
  462. #endif // PRIMITIV_MSGPACK_WRITER_H_