msgpack 0.6.0pre1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +26 -0
  4. data/ChangeLog +117 -0
  5. data/Dockerfile +30 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +177 -0
  8. data/README.rdoc +129 -0
  9. data/Rakefile +114 -0
  10. data/bench/pack.rb +23 -0
  11. data/bench/pack_log.rb +33 -0
  12. data/bench/pack_log_long.rb +65 -0
  13. data/bench/run.sh +14 -0
  14. data/bench/run_long.sh +35 -0
  15. data/bench/unpack.rb +21 -0
  16. data/bench/unpack_log.rb +34 -0
  17. data/bench/unpack_log_long.rb +67 -0
  18. data/cross-build.sh +9 -0
  19. data/doclib/msgpack/buffer.rb +193 -0
  20. data/doclib/msgpack/core_ext.rb +101 -0
  21. data/doclib/msgpack/error.rb +14 -0
  22. data/doclib/msgpack/packer.rb +134 -0
  23. data/doclib/msgpack/unpacker.rb +146 -0
  24. data/doclib/msgpack.rb +77 -0
  25. data/ext/java/org/msgpack/jruby/Buffer.java +221 -0
  26. data/ext/java/org/msgpack/jruby/Decoder.java +201 -0
  27. data/ext/java/org/msgpack/jruby/Encoder.java +308 -0
  28. data/ext/java/org/msgpack/jruby/ExtensionValue.java +136 -0
  29. data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +107 -0
  30. data/ext/java/org/msgpack/jruby/Packer.java +78 -0
  31. data/ext/java/org/msgpack/jruby/Types.java +37 -0
  32. data/ext/java/org/msgpack/jruby/Unpacker.java +170 -0
  33. data/ext/msgpack/buffer.c +695 -0
  34. data/ext/msgpack/buffer.h +447 -0
  35. data/ext/msgpack/buffer_class.c +507 -0
  36. data/ext/msgpack/buffer_class.h +32 -0
  37. data/ext/msgpack/compat.h +113 -0
  38. data/ext/msgpack/core_ext.c +129 -0
  39. data/ext/msgpack/core_ext.h +26 -0
  40. data/ext/msgpack/extconf.rb +28 -0
  41. data/ext/msgpack/packer.c +168 -0
  42. data/ext/msgpack/packer.h +441 -0
  43. data/ext/msgpack/packer_class.c +302 -0
  44. data/ext/msgpack/packer_class.h +30 -0
  45. data/ext/msgpack/rbinit.c +33 -0
  46. data/ext/msgpack/rmem.c +94 -0
  47. data/ext/msgpack/rmem.h +109 -0
  48. data/ext/msgpack/sysdep.h +115 -0
  49. data/ext/msgpack/sysdep_endian.h +50 -0
  50. data/ext/msgpack/sysdep_types.h +46 -0
  51. data/ext/msgpack/unpacker.c +771 -0
  52. data/ext/msgpack/unpacker.h +122 -0
  53. data/ext/msgpack/unpacker_class.c +405 -0
  54. data/ext/msgpack/unpacker_class.h +32 -0
  55. data/lib/msgpack/msgpack.so +0 -0
  56. data/lib/msgpack/version.rb +3 -0
  57. data/lib/msgpack.rb +13 -0
  58. data/msgpack.gemspec +31 -0
  59. data/msgpack.org.md +46 -0
  60. data/spec/cases.json +1 -0
  61. data/spec/cases.msg +0 -0
  62. data/spec/cases_compact.msg +0 -0
  63. data/spec/cases_spec.rb +39 -0
  64. data/spec/cruby/buffer_io_spec.rb +256 -0
  65. data/spec/cruby/buffer_packer.rb +29 -0
  66. data/spec/cruby/buffer_spec.rb +572 -0
  67. data/spec/cruby/buffer_unpacker.rb +19 -0
  68. data/spec/cruby/packer_spec.rb +120 -0
  69. data/spec/cruby/unpacker_spec.rb +305 -0
  70. data/spec/format_spec.rb +282 -0
  71. data/spec/jruby/benchmarks/shootout_bm.rb +73 -0
  72. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +25 -0
  73. data/spec/jruby/msgpack/unpacker_spec.rb +290 -0
  74. data/spec/jruby/msgpack_spec.rb +142 -0
  75. data/spec/pack_spec.rb +67 -0
  76. data/spec/random_compat.rb +24 -0
  77. data/spec/spec_helper.rb +27 -0
  78. data/spec/unpack_spec.rb +60 -0
  79. metadata +209 -0
@@ -0,0 +1,695 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2013 Sadayuki Furuhashi
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #include "buffer.h"
20
+ #include "rmem.h"
21
+
22
+ #ifndef HAVE_RB_STR_REPLACE
23
+ static ID s_replace;
24
+ #endif
25
+
26
+ #ifdef COMPAT_HAVE_ENCODING /* see compat.h*/
27
+ int msgpack_rb_encindex_utf8;
28
+ int msgpack_rb_encindex_usascii;
29
+ int msgpack_rb_encindex_ascii8bit;
30
+ #endif
31
+
32
+ #ifndef DISABLE_RMEM
33
+ static msgpack_rmem_t s_rmem;
34
+ #endif
35
+
36
+ void msgpack_buffer_static_init()
37
+ {
38
+ #ifdef COMPAT_HAVE_ENCODING
39
+ msgpack_rb_encindex_utf8 = rb_utf8_encindex();
40
+ msgpack_rb_encindex_usascii = rb_usascii_encindex();
41
+ msgpack_rb_encindex_ascii8bit = rb_ascii8bit_encindex();
42
+ #endif
43
+
44
+ #ifndef DISABLE_RMEM
45
+ msgpack_rmem_init(&s_rmem);
46
+ #endif
47
+
48
+ #ifndef HAVE_RB_STR_REPLACE
49
+ s_replace = rb_intern("replace");
50
+ #endif
51
+ }
52
+
53
+ void msgpack_buffer_static_destroy()
54
+ {
55
+ #ifndef DISABLE_RMEM
56
+ msgpack_rmem_destroy(&s_rmem);
57
+ #endif
58
+ }
59
+
60
+ void msgpack_buffer_init(msgpack_buffer_t* b)
61
+ {
62
+ memset(b, 0, sizeof(msgpack_buffer_t));
63
+
64
+ b->head = &b->tail;
65
+ b->write_reference_threshold = MSGPACK_BUFFER_STRING_WRITE_REFERENCE_DEFAULT;
66
+ b->read_reference_threshold = MSGPACK_BUFFER_STRING_READ_REFERENCE_DEFAULT;
67
+ b->io_buffer_size = MSGPACK_BUFFER_IO_BUFFER_SIZE_DEFAULT;
68
+ b->io = Qnil;
69
+ b->io_buffer = Qnil;
70
+ }
71
+
72
+ static void _msgpack_buffer_chunk_destroy(msgpack_buffer_chunk_t* c)
73
+ {
74
+ if(c->mem != NULL) {
75
+ #ifndef DISABLE_RMEM
76
+ if(!msgpack_rmem_free(&s_rmem, c->mem)) {
77
+ free(c->mem);
78
+ }
79
+ /* no needs to update rmem_owner because chunks will not be
80
+ * free()ed (left in free_list) and thus *rmem_owner is
81
+ * always valid. */
82
+ #else
83
+ free(c->mem);
84
+ #endif
85
+ }
86
+ c->first = NULL;
87
+ c->last = NULL;
88
+ c->mem = NULL;
89
+ }
90
+
91
+ void msgpack_buffer_destroy(msgpack_buffer_t* b)
92
+ {
93
+ /* head is always available */
94
+ msgpack_buffer_chunk_t* c = b->head;
95
+ while(c != &b->tail) {
96
+ msgpack_buffer_chunk_t* n = c->next;
97
+ _msgpack_buffer_chunk_destroy(c);
98
+ free(c);
99
+ c = n;
100
+ }
101
+ _msgpack_buffer_chunk_destroy(c);
102
+
103
+ c = b->free_list;
104
+ while(c != NULL) {
105
+ msgpack_buffer_chunk_t* n = c->next;
106
+ free(c);
107
+ c = n;
108
+ }
109
+ }
110
+
111
+ void msgpack_buffer_mark(msgpack_buffer_t* b)
112
+ {
113
+ /* head is always available */
114
+ msgpack_buffer_chunk_t* c = b->head;
115
+ while(c != &b->tail) {
116
+ rb_gc_mark(c->mapped_string);
117
+ c = c->next;
118
+ }
119
+ rb_gc_mark(c->mapped_string);
120
+
121
+ rb_gc_mark(b->io);
122
+ rb_gc_mark(b->io_buffer);
123
+
124
+ rb_gc_mark(b->owner);
125
+ }
126
+
127
+ bool _msgpack_buffer_shift_chunk(msgpack_buffer_t* b)
128
+ {
129
+ _msgpack_buffer_chunk_destroy(b->head);
130
+
131
+ if(b->head == &b->tail) {
132
+ /* list becomes empty. don't add head to free_list
133
+ * because head should be always available */
134
+ b->tail_buffer_end = NULL;
135
+ b->read_buffer = NULL;
136
+ return false;
137
+ }
138
+
139
+ /* add head to free_list */
140
+ msgpack_buffer_chunk_t* next_head = b->head->next;
141
+ b->head->next = b->free_list;
142
+ b->free_list = b->head;
143
+
144
+ b->head = next_head;
145
+ b->read_buffer = next_head->first;
146
+
147
+ return true;
148
+ }
149
+
150
+ void msgpack_buffer_clear(msgpack_buffer_t* b)
151
+ {
152
+ while(_msgpack_buffer_shift_chunk(b)) {
153
+ ;
154
+ }
155
+ }
156
+
157
+ size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string, size_t length)
158
+ {
159
+ size_t avail = msgpack_buffer_top_readable_size(b);
160
+
161
+ #ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE
162
+ /* optimize */
163
+ if(length <= avail && RSTRING_LEN(string) == 0 &&
164
+ b->head->mapped_string != NO_MAPPED_STRING &&
165
+ length >= b->read_reference_threshold) {
166
+ VALUE s = _msgpack_buffer_refer_head_mapped_string(b, length);
167
+ #ifndef HAVE_RB_STR_REPLACE
168
+ /* TODO MRI 1.8 */
169
+ rb_funcall(string, s_replace, 1, s);
170
+ #else
171
+ rb_str_replace(string, s);
172
+ #endif
173
+ /* here doesn't have to call ENCODING_SET because
174
+ * encoding of s is always ASCII-8BIT */
175
+ _msgpack_buffer_consumed(b, length);
176
+ return length;
177
+ }
178
+ #endif
179
+
180
+ size_t const length_orig = length;
181
+
182
+ while(true) {
183
+ if(length <= avail) {
184
+ rb_str_buf_cat(string, b->read_buffer, length);
185
+ _msgpack_buffer_consumed(b, length);
186
+ return length_orig;
187
+ }
188
+
189
+ rb_str_buf_cat(string, b->read_buffer, avail);
190
+ length -= avail;
191
+
192
+ if(!_msgpack_buffer_shift_chunk(b)) {
193
+ return length_orig - length;
194
+ }
195
+
196
+ avail = msgpack_buffer_top_readable_size(b);
197
+ }
198
+ }
199
+
200
+ size_t msgpack_buffer_read_nonblock(msgpack_buffer_t* b, char* buffer, size_t length)
201
+ {
202
+ /* buffer == NULL means skip */
203
+ size_t const length_orig = length;
204
+
205
+ while(true) {
206
+ size_t avail = msgpack_buffer_top_readable_size(b);
207
+
208
+ if(length <= avail) {
209
+ if(buffer != NULL) {
210
+ memcpy(buffer, b->read_buffer, length);
211
+ }
212
+ _msgpack_buffer_consumed(b, length);
213
+ return length_orig;
214
+ }
215
+
216
+ if(buffer != NULL) {
217
+ memcpy(buffer, b->read_buffer, avail);
218
+ buffer += avail;
219
+ }
220
+ length -= avail;
221
+
222
+ if(!_msgpack_buffer_shift_chunk(b)) {
223
+ return length_orig - length;
224
+ }
225
+ }
226
+ }
227
+
228
+ size_t msgpack_buffer_all_readable_size(const msgpack_buffer_t* b)
229
+ {
230
+ size_t sz = msgpack_buffer_top_readable_size(b);
231
+
232
+ if(b->head == &b->tail) {
233
+ return sz;
234
+ }
235
+
236
+ msgpack_buffer_chunk_t* c = b->head->next;
237
+
238
+ while(true) {
239
+ sz += c->last - c->first;
240
+ if(c == &b->tail) {
241
+ return sz;
242
+ }
243
+ c = c->next;
244
+ }
245
+ }
246
+
247
+ bool _msgpack_buffer_read_all2(msgpack_buffer_t* b, char* buffer, size_t length)
248
+ {
249
+ if(!msgpack_buffer_ensure_readable(b, length)) {
250
+ return false;
251
+ }
252
+
253
+ msgpack_buffer_read_nonblock(b, buffer, length);
254
+ return true;
255
+ }
256
+
257
+
258
+ static inline msgpack_buffer_chunk_t* _msgpack_buffer_alloc_new_chunk(msgpack_buffer_t* b)
259
+ {
260
+ msgpack_buffer_chunk_t* reuse = b->free_list;
261
+ if(reuse == NULL) {
262
+ return malloc(sizeof(msgpack_buffer_chunk_t));
263
+ }
264
+ b->free_list = b->free_list->next;
265
+ return reuse;
266
+ }
267
+
268
+ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
269
+ {
270
+ if(b->head == &b->tail) {
271
+ if(b->tail.first == NULL) {
272
+ /* empty buffer */
273
+ return;
274
+ }
275
+
276
+ msgpack_buffer_chunk_t* nc = _msgpack_buffer_alloc_new_chunk(b);
277
+
278
+ *nc = b->tail;
279
+ b->head = nc;
280
+ nc->next = &b->tail;
281
+
282
+ } else {
283
+ /* search node before tail */
284
+ msgpack_buffer_chunk_t* before_tail = b->head;
285
+ while(before_tail->next != &b->tail) {
286
+ before_tail = before_tail->next;
287
+ }
288
+
289
+ msgpack_buffer_chunk_t* nc = _msgpack_buffer_alloc_new_chunk(b);
290
+
291
+ #ifndef DISABLE_RMEM
292
+ #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT
293
+ if(b->rmem_last == b->tail_buffer_end) {
294
+ /* reuse unused rmem space */
295
+ size_t unused = b->tail_buffer_end - b->tail.last;
296
+ b->rmem_last -= unused;
297
+ }
298
+ #endif
299
+ #endif
300
+
301
+ /* rebuild tail */
302
+ *nc = b->tail;
303
+ before_tail->next = nc;
304
+ nc->next = &b->tail;
305
+ }
306
+ }
307
+
308
+ static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
309
+ {
310
+ VALUE mapped_string = rb_str_dup(string);
311
+ #ifdef COMPAT_HAVE_ENCODING
312
+ ENCODING_SET(mapped_string, msgpack_rb_encindex_ascii8bit);
313
+ #endif
314
+
315
+ _msgpack_buffer_add_new_chunk(b);
316
+
317
+ char* data = RSTRING_PTR(mapped_string);
318
+ size_t length = RSTRING_LEN(mapped_string);
319
+
320
+ b->tail.first = (char*) data;
321
+ b->tail.last = (char*) data + length;
322
+ b->tail.mapped_string = mapped_string;
323
+ b->tail.mem = NULL;
324
+
325
+ /* msgpack_buffer_writable_size should return 0 for mapped chunk */
326
+ b->tail_buffer_end = b->tail.last;
327
+
328
+ /* consider read_buffer */
329
+ if(b->head == &b->tail) {
330
+ b->read_buffer = b->tail.first;
331
+ }
332
+ }
333
+
334
+ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
335
+ {
336
+ size_t length = RSTRING_LEN(string);
337
+
338
+ if(b->io != Qnil) {
339
+ msgpack_buffer_flush(b);
340
+ #ifdef COMPAT_HAVE_ENCODING
341
+ if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
342
+ rb_funcall(b->io, b->io_write_all_method, 1, string);
343
+ } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
344
+ VALUE s = rb_str_dup(string);
345
+ ENCODING_SET(s, msgpack_rb_encindex_ascii8bit);
346
+ rb_funcall(b->io, b->io_write_all_method, 1, s);
347
+ } else {
348
+ msgpack_buffer_append(b, RSTRING_PTR(string), length);
349
+ }
350
+ #else
351
+ rb_funcall(b->io, b->io_write_all_method, 1, string);
352
+ #endif
353
+
354
+ } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
355
+ _msgpack_buffer_append_reference(b, string);
356
+
357
+ } else {
358
+ msgpack_buffer_append(b, RSTRING_PTR(string), length);
359
+ }
360
+ }
361
+
362
+ static inline void* _msgpack_buffer_chunk_malloc(
363
+ msgpack_buffer_t* b, msgpack_buffer_chunk_t* c,
364
+ size_t required_size, size_t* allocated_size)
365
+ {
366
+ #ifndef DISABLE_RMEM
367
+ if(required_size <= MSGPACK_RMEM_PAGE_SIZE) {
368
+ #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT
369
+ if((size_t)(b->rmem_end - b->rmem_last) < required_size) {
370
+ #endif
371
+ /* alloc new rmem page */
372
+ *allocated_size = MSGPACK_RMEM_PAGE_SIZE;
373
+ char* buffer = msgpack_rmem_alloc(&s_rmem);
374
+ c->mem = buffer;
375
+
376
+ /* update rmem owner */
377
+ b->rmem_owner = &c->mem;
378
+ b->rmem_last = b->rmem_end = buffer + MSGPACK_RMEM_PAGE_SIZE;
379
+
380
+ return buffer;
381
+
382
+ #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT
383
+ } else {
384
+ /* reuse unused rmem */
385
+ *allocated_size = (size_t)(b->rmem_end - b->rmem_last);
386
+ char* buffer = b->rmem_last;
387
+ b->rmem_last = b->rmem_end;
388
+
389
+ /* update rmem owner */
390
+ c->mem = *b->rmem_owner;
391
+ *b->rmem_owner = NULL;
392
+ b->rmem_owner = &c->mem;
393
+
394
+ return buffer;
395
+ }
396
+ #endif
397
+ }
398
+ #else
399
+ if(required_size < 72) {
400
+ required_size = 72;
401
+ }
402
+ #endif
403
+
404
+ // TODO alignment?
405
+ *allocated_size = required_size;
406
+ void* mem = malloc(required_size);
407
+ c->mem = mem;
408
+ return mem;
409
+ }
410
+
411
+ static inline void* _msgpack_buffer_chunk_realloc(
412
+ msgpack_buffer_t* b, msgpack_buffer_chunk_t* c,
413
+ void* mem, size_t required_size, size_t* current_size)
414
+ {
415
+ if(mem == NULL) {
416
+ return _msgpack_buffer_chunk_malloc(b, c, required_size, current_size);
417
+ }
418
+
419
+ size_t next_size = *current_size * 2;
420
+ while(next_size < required_size) {
421
+ next_size *= 2;
422
+ }
423
+ *current_size = next_size;
424
+ mem = realloc(mem, next_size);
425
+
426
+ c->mem = mem;
427
+ return mem;
428
+ }
429
+
430
+ void _msgpack_buffer_expand(msgpack_buffer_t* b, const char* data, size_t length, bool flush_to_io)
431
+ {
432
+ if(flush_to_io && b->io != Qnil) {
433
+ msgpack_buffer_flush(b);
434
+ if(msgpack_buffer_writable_size(b) >= length) {
435
+ /* data == NULL means ensure_writable */
436
+ if(data != NULL) {
437
+ size_t tail_avail = msgpack_buffer_writable_size(b);
438
+ memcpy(b->tail.last, data, length);
439
+ b->tail.last += tail_avail;
440
+ }
441
+ return;
442
+ }
443
+ }
444
+
445
+ /* data == NULL means ensure_writable */
446
+ if(data != NULL) {
447
+ size_t tail_avail = msgpack_buffer_writable_size(b);
448
+ memcpy(b->tail.last, data, tail_avail);
449
+ b->tail.last += tail_avail;
450
+ data += tail_avail;
451
+ length -= tail_avail;
452
+ }
453
+
454
+ size_t capacity = b->tail.last - b->tail.first;
455
+
456
+ /* can't realloc mapped chunk or rmem page */
457
+ if(b->tail.mapped_string != NO_MAPPED_STRING
458
+ #ifndef DISABLE_RMEM
459
+ || capacity <= MSGPACK_RMEM_PAGE_SIZE
460
+ #endif
461
+ ) {
462
+ /* allocate new chunk */
463
+ _msgpack_buffer_add_new_chunk(b);
464
+
465
+ char* mem = _msgpack_buffer_chunk_malloc(b, &b->tail, length, &capacity);
466
+
467
+ char* last = mem;
468
+ if(data != NULL) {
469
+ memcpy(mem, data, length);
470
+ last += length;
471
+ }
472
+
473
+ /* rebuild tail chunk */
474
+ b->tail.first = mem;
475
+ b->tail.last = last;
476
+ b->tail.mapped_string = NO_MAPPED_STRING;
477
+ b->tail_buffer_end = mem + capacity;
478
+
479
+ /* consider read_buffer */
480
+ if(b->head == &b->tail) {
481
+ b->read_buffer = b->tail.first;
482
+ }
483
+
484
+ } else {
485
+ /* realloc malloc()ed chunk or NULL */
486
+ size_t tail_filled = b->tail.last - b->tail.first;
487
+ char* mem = _msgpack_buffer_chunk_realloc(b, &b->tail,
488
+ b->tail.first, tail_filled+length, &capacity);
489
+
490
+ char* last = mem + tail_filled;
491
+ if(data != NULL) {
492
+ memcpy(last, data, length);
493
+ last += length;
494
+ }
495
+
496
+ /* consider read_buffer */
497
+ if(b->head == &b->tail) {
498
+ size_t read_offset = b->read_buffer - b->head->first;
499
+ b->read_buffer = mem + read_offset;
500
+ }
501
+
502
+ /* rebuild tail chunk */
503
+ b->tail.first = mem;
504
+ b->tail.last = last;
505
+ b->tail_buffer_end = mem + capacity;
506
+ }
507
+ }
508
+
509
+ static inline VALUE _msgpack_buffer_head_chunk_as_string(msgpack_buffer_t* b)
510
+ {
511
+ size_t length = b->head->last - b->read_buffer;
512
+ if(length == 0) {
513
+ return rb_str_buf_new(0);
514
+ }
515
+
516
+ if(b->head->mapped_string != NO_MAPPED_STRING) {
517
+ return _msgpack_buffer_refer_head_mapped_string(b, length);
518
+ }
519
+
520
+ return rb_str_new(b->read_buffer, length);
521
+ }
522
+
523
+ static inline VALUE _msgpack_buffer_chunk_as_string(msgpack_buffer_chunk_t* c)
524
+ {
525
+ size_t chunk_size = c->last - c->first;
526
+ if(chunk_size == 0) {
527
+ return rb_str_buf_new(0);
528
+ }
529
+
530
+ if(c->mapped_string != NO_MAPPED_STRING) {
531
+ return rb_str_dup(c->mapped_string);
532
+ }
533
+
534
+ return rb_str_new(c->first, chunk_size);
535
+ }
536
+
537
+ VALUE msgpack_buffer_all_as_string(msgpack_buffer_t* b)
538
+ {
539
+ if(b->head == &b->tail) {
540
+ return _msgpack_buffer_head_chunk_as_string(b);
541
+ }
542
+
543
+ size_t length = msgpack_buffer_all_readable_size(b);
544
+ VALUE string = rb_str_new(NULL, length);
545
+ char* buffer = RSTRING_PTR(string);
546
+
547
+ size_t avail = msgpack_buffer_top_readable_size(b);
548
+ memcpy(buffer, b->read_buffer, avail);
549
+ buffer += avail;
550
+ length -= avail;
551
+
552
+ msgpack_buffer_chunk_t* c = b->head->next;
553
+
554
+ while(true) {
555
+ avail = c->last - c->first;
556
+ memcpy(buffer, c->first, avail);
557
+
558
+ if(length <= avail) {
559
+ return string;
560
+ }
561
+ buffer += avail;
562
+ length -= avail;
563
+
564
+ c = c->next;
565
+ }
566
+ }
567
+
568
+ VALUE msgpack_buffer_all_as_string_array(msgpack_buffer_t* b)
569
+ {
570
+ if(b->head == &b->tail) {
571
+ VALUE s = msgpack_buffer_all_as_string(b);
572
+ VALUE ary = rb_ary_new3(1, s);
573
+ return ary;
574
+ }
575
+
576
+ /* TODO optimize ary construction */
577
+ VALUE ary = rb_ary_new();
578
+
579
+ VALUE s = _msgpack_buffer_head_chunk_as_string(b);
580
+ rb_ary_push(ary, s);
581
+
582
+ msgpack_buffer_chunk_t* c = b->head->next;
583
+
584
+ while(true) {
585
+ s = _msgpack_buffer_chunk_as_string(c);
586
+ rb_ary_push(ary, s);
587
+ if(c == &b->tail) {
588
+ return ary;
589
+ }
590
+ c = c->next;
591
+ }
592
+
593
+ return ary;
594
+ }
595
+
596
+ size_t msgpack_buffer_flush_to_io(msgpack_buffer_t* b, VALUE io, ID write_method, bool consume)
597
+ {
598
+ if(msgpack_buffer_top_readable_size(b) == 0) {
599
+ return 0;
600
+ }
601
+
602
+ VALUE s = _msgpack_buffer_head_chunk_as_string(b);
603
+ rb_funcall(io, write_method, 1, s);
604
+ size_t sz = RSTRING_LEN(s);
605
+
606
+ if(consume) {
607
+ while(_msgpack_buffer_shift_chunk(b)) {
608
+ s = _msgpack_buffer_chunk_as_string(b->head);
609
+ rb_funcall(io, write_method, 1, s);
610
+ sz += RSTRING_LEN(s);
611
+ }
612
+ return sz;
613
+
614
+ } else {
615
+ if(b->head == &b->tail) {
616
+ return sz;
617
+ }
618
+ msgpack_buffer_chunk_t* c = b->head->next;
619
+ while(true) {
620
+ s = _msgpack_buffer_chunk_as_string(c);
621
+ rb_funcall(io, write_method, 1, s);
622
+ sz += RSTRING_LEN(s);
623
+ if(c == &b->tail) {
624
+ return sz;
625
+ }
626
+ c = c->next;
627
+ }
628
+ }
629
+ }
630
+
631
+ size_t _msgpack_buffer_feed_from_io(msgpack_buffer_t* b)
632
+ {
633
+ if(b->io_buffer == Qnil) {
634
+ b->io_buffer = rb_funcall(b->io, b->io_partial_read_method, 1, LONG2NUM(b->io_buffer_size));
635
+ if(b->io_buffer == Qnil) {
636
+ rb_raise(rb_eEOFError, "IO reached end of file");
637
+ }
638
+ StringValue(b->io_buffer);
639
+ } else {
640
+ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(b->io_buffer_size), b->io_buffer);
641
+ if(ret == Qnil) {
642
+ rb_raise(rb_eEOFError, "IO reached end of file");
643
+ }
644
+ }
645
+
646
+ size_t len = RSTRING_LEN(b->io_buffer);
647
+ if(len == 0) {
648
+ rb_raise(rb_eEOFError, "IO reached end of file");
649
+ }
650
+
651
+ /* TODO zero-copy optimize? */
652
+ msgpack_buffer_append_nonblock(b, RSTRING_PTR(b->io_buffer), len);
653
+
654
+ return len;
655
+ }
656
+
657
+ size_t _msgpack_buffer_read_from_io_to_string(msgpack_buffer_t* b, VALUE string, size_t length)
658
+ {
659
+ if(RSTRING_LEN(string) == 0) {
660
+ /* direct read */
661
+ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), string);
662
+ if(ret == Qnil) {
663
+ return 0;
664
+ }
665
+ return RSTRING_LEN(string);
666
+ }
667
+
668
+ /* copy via io_buffer */
669
+ if(b->io_buffer == Qnil) {
670
+ b->io_buffer = rb_str_buf_new(0);
671
+ }
672
+
673
+ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), b->io_buffer);
674
+ if(ret == Qnil) {
675
+ return 0;
676
+ }
677
+ size_t rl = RSTRING_LEN(b->io_buffer);
678
+
679
+ rb_str_buf_cat(string, (const void*)RSTRING_PTR(b->io_buffer), rl);
680
+ return rl;
681
+ }
682
+
683
+ size_t _msgpack_buffer_skip_from_io(msgpack_buffer_t* b, size_t length)
684
+ {
685
+ if(b->io_buffer == Qnil) {
686
+ b->io_buffer = rb_str_buf_new(0);
687
+ }
688
+
689
+ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), b->io_buffer);
690
+ if(ret == Qnil) {
691
+ return 0;
692
+ }
693
+ return RSTRING_LEN(b->io_buffer);
694
+ }
695
+