]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | // This source code is licensed under both the GPLv2 (found in the | |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
7c673cae FG |
5 | |
6 | /* | |
7 | * This header file defines FbsonInBuffer and FbsonOutStream classes. | |
8 | * | |
9 | * ** Input Buffer ** | |
10 | * FbsonInBuffer is a customer input buffer to wrap raw character buffer. Its | |
11 | * object instances are used to create std::istream objects interally. | |
12 | * | |
13 | * ** Output Stream ** | |
14 | * FbsonOutStream is a custom output stream classes, to contain the FBSON | |
15 | * serialized binary. The class is conveniently used to specialize templates of | |
16 | * FbsonParser and FbsonWriter. | |
17 | * | |
18 | * @author Tian Xia <tianx@fb.com> | |
19 | */ | |
20 | ||
11fdf7f2 | 21 | #pragma once |
7c673cae FG |
22 | |
23 | #ifndef __STDC_FORMAT_MACROS | |
24 | #define __STDC_FORMAT_MACROS | |
25 | #endif | |
26 | ||
27 | #if defined OS_WIN && !defined snprintf | |
28 | #define snprintf _snprintf | |
29 | #endif | |
30 | ||
31 | #include <inttypes.h> | |
32 | #include <iostream> | |
33 | ||
34 | namespace fbson { | |
35 | ||
36 | // lengths includes sign | |
37 | #define MAX_INT_DIGITS 11 | |
38 | #define MAX_INT64_DIGITS 20 | |
39 | #define MAX_DOUBLE_DIGITS 23 // 1(sign)+16(significant)+1(decimal)+5(exponent) | |
40 | ||
41 | /* | |
42 | * FBSON's implementation of input buffer | |
43 | */ | |
44 | class FbsonInBuffer : public std::streambuf { | |
45 | public: | |
46 | FbsonInBuffer(const char* str, uint32_t len) { | |
47 | // this is read buffer and the str will not be changed | |
48 | // so we use const_cast (ugly!) to remove constness | |
49 | char* pch(const_cast<char*>(str)); | |
50 | setg(pch, pch, pch + len); | |
51 | } | |
52 | }; | |
53 | ||
54 | /* | |
55 | * FBSON's implementation of output stream. | |
56 | * | |
57 | * This is a wrapper of a char buffer. By default, the buffer capacity is 1024 | |
58 | * bytes. We will double the buffer if realloc is needed for writes. | |
59 | */ | |
60 | class FbsonOutStream : public std::ostream { | |
61 | public: | |
62 | explicit FbsonOutStream(uint32_t capacity = 1024) | |
63 | : std::ostream(nullptr), | |
64 | head_(nullptr), | |
65 | size_(0), | |
66 | capacity_(capacity), | |
67 | alloc_(true) { | |
68 | if (capacity_ == 0) { | |
69 | capacity_ = 1024; | |
70 | } | |
71 | ||
72 | head_ = (char*)malloc(capacity_); | |
73 | } | |
74 | ||
75 | FbsonOutStream(char* buffer, uint32_t capacity) | |
76 | : std::ostream(nullptr), | |
77 | head_(buffer), | |
78 | size_(0), | |
79 | capacity_(capacity), | |
80 | alloc_(false) { | |
81 | assert(buffer && capacity_ > 0); | |
82 | } | |
83 | ||
84 | ~FbsonOutStream() { | |
85 | if (alloc_) { | |
86 | free(head_); | |
87 | } | |
88 | } | |
89 | ||
90 | void put(char c) { write(&c, 1); } | |
91 | ||
92 | void write(const char* c_str) { write(c_str, (uint32_t)strlen(c_str)); } | |
93 | ||
94 | void write(const char* bytes, uint32_t len) { | |
95 | if (len == 0) | |
96 | return; | |
97 | ||
98 | if (size_ + len > capacity_) { | |
99 | realloc(len); | |
100 | } | |
101 | ||
102 | memcpy(head_ + size_, bytes, len); | |
103 | size_ += len; | |
104 | } | |
105 | ||
106 | // write the integer to string | |
107 | void write(int i) { | |
108 | // snprintf automatically adds a NULL, so we need one more char | |
109 | if (size_ + MAX_INT_DIGITS + 1 > capacity_) { | |
110 | realloc(MAX_INT_DIGITS + 1); | |
111 | } | |
112 | ||
113 | int len = snprintf(head_ + size_, MAX_INT_DIGITS + 1, "%d", i); | |
114 | assert(len > 0); | |
115 | size_ += len; | |
116 | } | |
117 | ||
118 | // write the 64bit integer to string | |
119 | void write(int64_t l) { | |
120 | // snprintf automatically adds a NULL, so we need one more char | |
121 | if (size_ + MAX_INT64_DIGITS + 1 > capacity_) { | |
122 | realloc(MAX_INT64_DIGITS + 1); | |
123 | } | |
124 | ||
125 | int len = snprintf(head_ + size_, MAX_INT64_DIGITS + 1, "%" PRIi64, l); | |
126 | assert(len > 0); | |
127 | size_ += len; | |
128 | } | |
129 | ||
130 | // write the double to string | |
131 | void write(double d) { | |
132 | // snprintf automatically adds a NULL, so we need one more char | |
133 | if (size_ + MAX_DOUBLE_DIGITS + 1 > capacity_) { | |
134 | realloc(MAX_DOUBLE_DIGITS + 1); | |
135 | } | |
136 | ||
137 | int len = snprintf(head_ + size_, MAX_DOUBLE_DIGITS + 1, "%.15g", d); | |
138 | assert(len > 0); | |
139 | size_ += len; | |
140 | } | |
141 | ||
142 | pos_type tellp() const { return size_; } | |
143 | ||
144 | void seekp(pos_type pos) { size_ = (uint32_t)pos; } | |
145 | ||
146 | const char* getBuffer() const { return head_; } | |
147 | ||
148 | pos_type getSize() const { return tellp(); } | |
149 | ||
150 | private: | |
151 | void realloc(uint32_t len) { | |
152 | assert(capacity_ > 0); | |
153 | ||
154 | capacity_ *= 2; | |
155 | while (capacity_ < size_ + len) { | |
156 | capacity_ *= 2; | |
157 | } | |
158 | ||
159 | if (alloc_) { | |
160 | char* new_buf = (char*)::realloc(head_, capacity_); | |
161 | assert(new_buf); | |
162 | head_ = new_buf; | |
163 | } else { | |
164 | char* new_buf = (char*)::malloc(capacity_); | |
165 | assert(new_buf); | |
166 | memcpy(new_buf, head_, size_); | |
167 | head_ = new_buf; | |
168 | alloc_ = true; | |
169 | } | |
170 | } | |
171 | ||
172 | private: | |
173 | char* head_; | |
174 | uint32_t size_; | |
175 | uint32_t capacity_; | |
176 | bool alloc_; | |
177 | }; | |
178 | ||
179 | } // namespace fbson |