1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/boostorg/json
9 //
10 
11 // Test that header file is self-contained.
12 #include <boost/json/monotonic_resource.hpp>
13 
14 #include <boost/json/null_resource.hpp>
15 #include <boost/json/parse.hpp>
16 #include <boost/json/serialize.hpp>
17 #include <boost/json/detail/align.hpp>
18 #include <iostream>
19 
20 #include "test_suite.hpp"
21 
22 BOOST_JSON_NS_BEGIN
23 
24 BOOST_STATIC_ASSERT( std::is_nothrow_destructible<monotonic_resource>::value );
25 
26 class monotonic_resource_test
27 {
28 private:
29     bool
in_buffer(void * ptr,void * buffer,std::size_t buffer_size)30     in_buffer(
31         void* ptr,
32         void* buffer,
33         std::size_t buffer_size)
34     {
35         using ptr_t = const volatile unsigned char*;
36         return reinterpret_cast<ptr_t>(ptr) >= reinterpret_cast<ptr_t>(buffer) &&
37             reinterpret_cast<ptr_t>(ptr) < reinterpret_cast<ptr_t>(buffer) + buffer_size;
38     }
39 
40     bool
all_alloc_in_same_block(monotonic_resource & mr,std::size_t bytes,std::size_t align)41     all_alloc_in_same_block(
42         monotonic_resource& mr,
43         std::size_t bytes,
44         std::size_t align)
45     {
46         // base of the block
47         auto first = mr.allocate(align, align);
48         bool result = true;
49         for (auto allocs = (bytes - align) / align; allocs; --allocs)
50             result &= in_buffer(mr.allocate(align, align), first, bytes);
51         return result;
52     }
53 
54 public:
55     void
testJavadocs()56     testJavadocs()
57     {
58     //--------------------------------------
59 
60     unsigned char buf[4000];
61     monotonic_resource mr( buf );
62 
63     // Parse the string, using our memory resource
64     auto const jv = parse( "[1,2,3]", &mr );
65 
66     // Print the JSON
67     std::cout << jv;
68 
69     //--------------------------------------
70     }
71 
72     void
testMembers()73     testMembers()
74     {
75         // ~monotonic_resource
76         {
77             // implied
78         }
79 
80         // monotonic_resource(size_t, storage_ptr)
81         {
82             {
83                 monotonic_resource mr(1);
84             }
85             {
86                 monotonic_resource mr(5000);
87             }
88             {
89                 monotonic_resource mr(
90                     1, get_null_resource());
91             }
92             {
93                 monotonic_resource mr(
94                     5000, get_null_resource());
95             }
96         }
97 
98         // monotonic_resource(unsigned char*, size_t, storage_ptr)
99         {
100             {
101                 unsigned char buf[2000];
102                 monotonic_resource mr(
103                     &buf[0], sizeof(buf));
104             }
105             {
106                 unsigned char buf[2000];
107                 monotonic_resource mr(
108                     &buf[0], sizeof(buf),
109                         get_null_resource());
110             }
111         }
112 
113         // monotonic_resource(unsigned char[N], storage_ptr)
114         {
115             {
116                 unsigned char buf[2000];
117                 monotonic_resource mr(buf);
118             }
119             {
120                 unsigned char buf[2000];
121                 monotonic_resource mr(buf,
122                     get_null_resource());
123             }
124         }
125 
126     #ifdef __cpp_lib_byte
127         // monotonic_resource(std::byte[N], storage_ptr)
128         {
129             {
130                 std::byte buf[2000];
131                 monotonic_resource mr(buf);
132             }
133 
134             {
135                 std::byte buf[2000];
136                 monotonic_resource mr(buf,
137                     get_null_resource());
138             }
139         }
140     #endif
141 
142         // monotonic_resource(unsigned char[N], std::size_t, storage_ptr)
143         {
144             {
145                 unsigned char buf[2000];
146                 monotonic_resource mr(buf, 1000);
147             }
148             {
149                 unsigned char buf[2000];
150                 monotonic_resource mr(buf, 1000,
151                     get_null_resource());
152             }
153         }
154 
155     #ifdef __cpp_lib_byte
156         // monotonic_resource(unsigned char[N], std::size_t, storage_ptr)
157         {
158             {
159                 std::byte buf[2000];
160                 monotonic_resource mr(buf, 1000);
161             }
162             {
163                 std::byte buf[2000];
164                 monotonic_resource mr(buf, 1000,
165                     get_null_resource());
166             }
167         }
168     #endif
169 
170         // release()
171         {
172             unsigned char buf[10];
173             monotonic_resource mr(
174                 buf, sizeof(buf));
175             (void)mr.allocate(10,1);
176             mr.release();
177             (void)mr.allocate(10,1);
178         }
179 
180         // coverage
181         {
182             monotonic_resource mr(std::size_t(-1)-2);
183         }
184     }
185 
186     void
testGeneral()187     testGeneral()
188     {
189         // test that each block gets filled to capacity
190         // and if the growth factor is correct
191         {
192             monotonic_resource mr;
193             BOOST_TEST(all_alloc_in_same_block(mr, 1024, 1));
194             BOOST_TEST(all_alloc_in_same_block(mr, 2048, 2));
195             BOOST_TEST(all_alloc_in_same_block(mr, 4096, 1));
196             BOOST_TEST(all_alloc_in_same_block(mr, 8192, 4));
197             BOOST_TEST(all_alloc_in_same_block(mr, 16384, 1));
198             BOOST_TEST(all_alloc_in_same_block(mr, 32768, 8));
199             BOOST_TEST(all_alloc_in_same_block(mr, 65536, 1));
200         }
201         // test if each allocation is aligned correctly
202         {
203             monotonic_resource mr;
204             for (std::size_t i = 0; i < 4096; ++i)
205             {
206                 const auto size = ((i * 3) % 32) + 1;
207                 std::size_t next = 1;
208                 for (auto mod = i % alignof(detail::max_align_t);
209                     mod; mod >>= 1, next <<= 1);
210                 const auto align = (std::max)(next,
211                     std::size_t(1));
212                 BOOST_TEST(!(reinterpret_cast<std::uintptr_t>(mr.allocate(size, align)) % align));
213             }
214         }
215         // test if user provided sizes are correctly rounded
216         {
217             {
218                 monotonic_resource mr(10);
219                 BOOST_TEST(all_alloc_in_same_block(mr, 1024, 1));
220             }
221             {
222                 monotonic_resource mr(1025);
223                 BOOST_TEST(all_alloc_in_same_block(mr, 2048, 1));
224             }
225             {
226                 monotonic_resource mr(4000);
227                 BOOST_TEST(all_alloc_in_same_block(mr, 4096, 1));
228             }
229         }
230         // test if sizes are correctly determined from initial buffers
231         {
232             {
233                 unsigned char buf[512];
234                 monotonic_resource mr(buf, 512);
235                 BOOST_TEST(all_alloc_in_same_block(mr, 512, 1));
236                 BOOST_TEST(all_alloc_in_same_block(mr, 1024, 1));
237             }
238             {
239                 unsigned char buf[2048];
240                 monotonic_resource mr(buf, 2048);
241                 BOOST_TEST(all_alloc_in_same_block(mr, 2048, 1));
242                 BOOST_TEST(all_alloc_in_same_block(mr, 4096, 1));
243             }
244             {
245                 unsigned char buf[4000];
246                 monotonic_resource mr(buf, 4000);
247                 BOOST_TEST(all_alloc_in_same_block(mr, 4000, 1));
248                 BOOST_TEST(all_alloc_in_same_block(mr, 4096, 1));
249             }
250         }
251         // test if allocations that exceed the block size cause rounding to occur
252         {
253             {
254                 monotonic_resource mr;
255                 auto p = mr.allocate(2048);
256                 (void)p;
257                 BOOST_TEST(all_alloc_in_same_block(mr, 4096, 1));
258             }
259             {
260                 monotonic_resource mr;
261                 void* p;
262                 p = mr.allocate(2000, 1);
263                 p = mr.allocate(48, 1);
264                 (void)p;
265                 BOOST_TEST(all_alloc_in_same_block(mr, 4096, 1));
266             }
267         }
268     }
269 
270     void
testStorage()271     testStorage()
272     {
273         auto jv = parse(
274 R"xx({
275     "glossary": {
276         "title": "example glossary",
277 		"GlossDiv": {
278             "title": "S",
279 			"GlossList": {
280                 "GlossEntry": {
281                     "ID": "SGML",
282 					"SortAs": "SGML",
283 					"GlossTerm": "Standard Generalized Markup Language",
284 					"Acronym": "SGML",
285 					"Abbrev": "ISO 8879:1986",
286 					"GlossDef": {
287                         "para": "A meta-markup language, used to create markup languages such as DocBook.",
288 						"GlossSeeAlso": ["GML", "XML"]
289                     },
290 					"GlossSee": "markup"
291                 }
292             }
293         }
294     }
295 })xx"
296         , make_shared_resource<monotonic_resource>());
297         BOOST_TEST_PASS();
298     }
299 
300     void
run()301     run()
302     {
303         testMembers();
304         testStorage();
305         testGeneral();
306     }
307 };
308 
309 TEST_SUITE(monotonic_resource_test, "boost.json.monotonic_resource");
310 
311 BOOST_JSON_NS_END
312