json 1.0.0 → 2.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +503 -0
  3. data/LICENSE +56 -0
  4. data/README.md +416 -0
  5. data/ext/json/ext/fbuffer/fbuffer.h +187 -0
  6. data/ext/json/ext/generator/depend +1 -0
  7. data/ext/json/ext/generator/extconf.rb +2 -7
  8. data/ext/json/ext/generator/generator.c +1312 -338
  9. data/ext/json/ext/generator/generator.h +177 -0
  10. data/ext/json/ext/parser/depend +1 -0
  11. data/ext/json/ext/parser/extconf.rb +28 -5
  12. data/ext/json/ext/parser/parser.c +1349 -689
  13. data/ext/json/ext/parser/parser.h +96 -0
  14. data/ext/json/ext/parser/parser.rl +644 -188
  15. data/ext/json/extconf.rb +3 -0
  16. data/json.gemspec +68 -0
  17. data/lib/json/add/bigdecimal.rb +58 -0
  18. data/lib/json/add/complex.rb +51 -0
  19. data/lib/json/add/core.rb +12 -0
  20. data/lib/json/add/date.rb +54 -0
  21. data/lib/json/add/date_time.rb +67 -0
  22. data/lib/json/add/exception.rb +49 -0
  23. data/lib/json/add/ostruct.rb +54 -0
  24. data/lib/json/add/range.rb +54 -0
  25. data/lib/json/add/rational.rb +49 -0
  26. data/lib/json/add/regexp.rb +48 -0
  27. data/lib/json/add/set.rb +48 -0
  28. data/lib/json/add/struct.rb +52 -0
  29. data/lib/json/add/symbol.rb +48 -0
  30. data/lib/json/add/time.rb +59 -0
  31. data/lib/json/common.rb +588 -74
  32. data/lib/json/ext.rb +3 -1
  33. data/lib/json/generic_object.rb +75 -0
  34. data/lib/json/pure/generator.rb +311 -119
  35. data/lib/json/pure/parser.rb +182 -55
  36. data/lib/json/pure.rb +5 -65
  37. data/lib/json/version.rb +2 -1
  38. data/lib/json.rb +583 -196
  39. metadata +78 -137
  40. data/CHANGES +0 -25
  41. data/GPL +0 -340
  42. data/README +0 -77
  43. data/Rakefile +0 -250
  44. data/TODO +0 -1
  45. data/VERSION +0 -1
  46. data/benchmarks/benchmark.txt +0 -133
  47. data/benchmarks/benchmark_generator.rb +0 -44
  48. data/benchmarks/benchmark_parser.rb +0 -22
  49. data/benchmarks/benchmark_rails.rb +0 -26
  50. data/bin/edit_json.rb +0 -11
  51. data/data/example.json +0 -1
  52. data/data/index.html +0 -37
  53. data/data/prototype.js +0 -2515
  54. data/ext/json/ext/generator/Makefile +0 -149
  55. data/ext/json/ext/generator/unicode.c +0 -184
  56. data/ext/json/ext/generator/unicode.h +0 -40
  57. data/ext/json/ext/parser/Makefile +0 -149
  58. data/ext/json/ext/parser/unicode.c +0 -156
  59. data/ext/json/ext/parser/unicode.h +0 -44
  60. data/install.rb +0 -26
  61. data/lib/json/Array.xpm +0 -21
  62. data/lib/json/FalseClass.xpm +0 -21
  63. data/lib/json/Hash.xpm +0 -21
  64. data/lib/json/Key.xpm +0 -73
  65. data/lib/json/NilClass.xpm +0 -21
  66. data/lib/json/Numeric.xpm +0 -28
  67. data/lib/json/String.xpm +0 -96
  68. data/lib/json/TrueClass.xpm +0 -21
  69. data/lib/json/editor.rb +0 -1207
  70. data/lib/json/json.xpm +0 -1499
  71. data/tests/fixtures/fail1.json +0 -1
  72. data/tests/fixtures/fail10.json +0 -1
  73. data/tests/fixtures/fail11.json +0 -1
  74. data/tests/fixtures/fail12.json +0 -1
  75. data/tests/fixtures/fail13.json +0 -1
  76. data/tests/fixtures/fail14.json +0 -1
  77. data/tests/fixtures/fail15.json +0 -1
  78. data/tests/fixtures/fail16.json +0 -1
  79. data/tests/fixtures/fail17.json +0 -1
  80. data/tests/fixtures/fail19.json +0 -1
  81. data/tests/fixtures/fail2.json +0 -1
  82. data/tests/fixtures/fail20.json +0 -1
  83. data/tests/fixtures/fail21.json +0 -1
  84. data/tests/fixtures/fail22.json +0 -1
  85. data/tests/fixtures/fail23.json +0 -1
  86. data/tests/fixtures/fail24.json +0 -1
  87. data/tests/fixtures/fail25.json +0 -1
  88. data/tests/fixtures/fail26.json +0 -1
  89. data/tests/fixtures/fail27.json +0 -2
  90. data/tests/fixtures/fail28.json +0 -2
  91. data/tests/fixtures/fail3.json +0 -1
  92. data/tests/fixtures/fail4.json +0 -1
  93. data/tests/fixtures/fail5.json +0 -1
  94. data/tests/fixtures/fail6.json +0 -1
  95. data/tests/fixtures/fail7.json +0 -1
  96. data/tests/fixtures/fail8.json +0 -1
  97. data/tests/fixtures/fail9.json +0 -1
  98. data/tests/fixtures/pass1.json +0 -56
  99. data/tests/fixtures/pass18.json +0 -1
  100. data/tests/fixtures/pass2.json +0 -1
  101. data/tests/fixtures/pass3.json +0 -6
  102. data/tests/runner.rb +0 -24
  103. data/tests/test_json.rb +0 -235
  104. data/tests/test_json_addition.rb +0 -94
  105. data/tests/test_json_fixtures.rb +0 -30
  106. data/tests/test_json_generate.rb +0 -81
  107. data/tests/test_json_unicode.rb +0 -55
  108. data/tools/fuzz.rb +0 -133
  109. data/tools/server.rb +0 -62
data/README.md ADDED
@@ -0,0 +1,416 @@
1
+ # JSON implementation for Ruby
2
+
3
+ [![CI](https://github.com/flori/json/actions/workflows/ci.yml/badge.svg)](https://github.com/flori/json/actions/workflows/ci.yml)
4
+
5
+ ## Description
6
+
7
+ This is a implementation of the JSON specification according to RFC 7159
8
+ http://www.ietf.org/rfc/rfc7159.txt . Starting from version 1.0.0 on there
9
+ will be two variants available:
10
+
11
+ * A pure ruby variant, that relies on the iconv and the stringscan
12
+ extensions, which are both part of the ruby standard library.
13
+ * The quite a bit faster native extension variant, which is in parts
14
+ implemented in C or Java and comes with its own unicode conversion
15
+ functions and a parser generated by the [Ragel] state machine compiler.
16
+
17
+ Both variants of the JSON generator generate UTF-8 character sequences by
18
+ default. If an :ascii\_only option with a true value is given, they escape all
19
+ non-ASCII and control characters with \uXXXX escape sequences, and support
20
+ UTF-16 surrogate pairs in order to be able to generate the whole range of
21
+ unicode code points.
22
+
23
+ All strings, that are to be encoded as JSON strings, should be UTF-8 byte
24
+ sequences on the Ruby side. To encode raw binary strings, that aren't UTF-8
25
+ encoded, please use the to\_json\_raw\_object method of String (which produces
26
+ an object, that contains a byte array) and decode the result on the receiving
27
+ endpoint.
28
+
29
+ ## Installation
30
+
31
+ It's recommended to use the extension variant of JSON, because it's faster than
32
+ the pure ruby variant. If you cannot build it on your system, you can settle
33
+ for the latter.
34
+
35
+ Just type into the command line as root:
36
+
37
+ ```
38
+ # rake install
39
+ ```
40
+
41
+ The above command will build the extensions and install them on your system.
42
+
43
+ ```
44
+ # rake install_pure
45
+ ```
46
+
47
+ or
48
+
49
+ ```
50
+ # ruby install.rb
51
+ ```
52
+
53
+ will just install the pure ruby implementation of JSON.
54
+
55
+ If you use Rubygems you can type
56
+
57
+ ```
58
+ # gem install json
59
+ ```
60
+
61
+ instead, to install the newest JSON version.
62
+
63
+ There is also a pure ruby json only variant of the gem, that can be installed
64
+ with:
65
+
66
+ ```
67
+ # gem install json_pure
68
+ ```
69
+
70
+ ## Compiling the extensions yourself
71
+
72
+ If you want to create the `parser.c` file from its `parser.rl` file or draw nice
73
+ graphviz images of the state machines, you need [Ragel].
74
+
75
+ ## Usage
76
+
77
+ To use JSON you can
78
+
79
+ ```ruby
80
+ require 'json'
81
+ ```
82
+
83
+ to load the installed variant (either the extension `'json'` or the pure
84
+ variant `'json_pure'`). If you have installed the extension variant, you can
85
+ pick either the extension variant or the pure variant by typing
86
+
87
+ ```ruby
88
+ require 'json/ext'
89
+ ```
90
+
91
+ or
92
+
93
+ ```ruby
94
+ require 'json/pure'
95
+ ```
96
+
97
+ Now you can parse a JSON document into a ruby data structure by calling
98
+
99
+ ```ruby
100
+ JSON.parse(document)
101
+ ```
102
+
103
+ If you want to generate a JSON document from a ruby data structure call
104
+ ```ruby
105
+ JSON.generate(data)
106
+ ```
107
+
108
+ You can also use the `pretty_generate` method (which formats the output more
109
+ verbosely and nicely) or `fast_generate` (which doesn't do any of the security
110
+ checks generate performs, e. g. nesting deepness checks).
111
+
112
+ There are also the JSON and JSON[] methods which use parse on a String or
113
+ generate a JSON document from an array or hash:
114
+
115
+ ```ruby
116
+ document = JSON 'test' => 23 # => "{\"test\":23}"
117
+ document = JSON['test' => 23] # => "{\"test\":23}"
118
+ ```
119
+
120
+ and
121
+
122
+ ```ruby
123
+ data = JSON '{"test":23}' # => {"test"=>23}
124
+ data = JSON['{"test":23}'] # => {"test"=>23}
125
+ ```
126
+
127
+ You can choose to load a set of common additions to ruby core's objects if
128
+ you
129
+
130
+ ```ruby
131
+ require 'json/add/core'
132
+ ```
133
+
134
+ After requiring this you can, e. g., serialise/deserialise Ruby ranges:
135
+
136
+ ```ruby
137
+ JSON JSON(1..10) # => 1..10
138
+ ```
139
+
140
+ To find out how to add JSON support to other or your own classes, read the
141
+ section "More Examples" below.
142
+
143
+ ## Serializing exceptions
144
+
145
+ The JSON module doesn't extend `Exception` by default. If you convert an `Exception`
146
+ object to JSON, it will by default only include the exception message.
147
+
148
+ To include the full details, you must either load the `json/add/core` mentioned
149
+ above, or specifically load the exception addition:
150
+
151
+ ```ruby
152
+ require 'json/add/exception'
153
+ ```
154
+
155
+ ## More Examples
156
+
157
+ To create a JSON document from a ruby data structure, you can call
158
+ `JSON.generate` like that:
159
+
160
+ ```ruby
161
+ json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
162
+ # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
163
+ ```
164
+
165
+ To get back a ruby data structure from a JSON document, you have to call
166
+ JSON.parse on it:
167
+
168
+ ```ruby
169
+ JSON.parse json
170
+ # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
171
+ ```
172
+
173
+ Note, that the range from the original data structure is a simple
174
+ string now. The reason for this is, that JSON doesn't support ranges
175
+ or arbitrary classes. In this case the json library falls back to call
176
+ `Object#to_json`, which is the same as `#to_s.to_json`.
177
+
178
+ It's possible to add JSON support serialization to arbitrary classes by
179
+ simply implementing a more specialized version of the `#to_json method`, that
180
+ should return a JSON object (a hash converted to JSON with `#to_json`) like
181
+ this (don't forget the `*a` for all the arguments):
182
+
183
+ ```ruby
184
+ class Range
185
+ def to_json(*a)
186
+ {
187
+ 'json_class' => self.class.name, # = 'Range'
188
+ 'data' => [ first, last, exclude_end? ]
189
+ }.to_json(*a)
190
+ end
191
+ end
192
+ ```
193
+
194
+ The hash key `json_class` is the class, that will be asked to deserialise the
195
+ JSON representation later. In this case it's `Range`, but any namespace of
196
+ the form `A::B` or `::A::B` will do. All other keys are arbitrary and can be
197
+ used to store the necessary data to configure the object to be deserialised.
198
+
199
+ If the key `json_class` is found in a JSON object, the JSON parser checks
200
+ if the given class responds to the `json_create` class method. If so, it is
201
+ called with the JSON object converted to a Ruby hash. So a range can
202
+ be deserialised by implementing `Range.json_create` like this:
203
+
204
+ ```ruby
205
+ class Range
206
+ def self.json_create(o)
207
+ new(*o['data'])
208
+ end
209
+ end
210
+ ```
211
+
212
+ Now it possible to serialise/deserialise ranges as well:
213
+
214
+ ```ruby
215
+ json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
216
+ # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
217
+ JSON.parse json
218
+ # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
219
+ json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
220
+ # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
221
+ JSON.parse json, :create_additions => true
222
+ # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
223
+ ```
224
+
225
+ `JSON.generate` always creates the shortest possible string representation of a
226
+ ruby data structure in one line. This is good for data storage or network
227
+ protocols, but not so good for humans to read. Fortunately there's also
228
+ `JSON.pretty_generate` (or `JSON.pretty_generate`) that creates a more readable
229
+ output:
230
+
231
+ ```ruby
232
+ puts JSON.pretty_generate([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
233
+ [
234
+ 1,
235
+ 2,
236
+ {
237
+ "a": 3.141
238
+ },
239
+ false,
240
+ true,
241
+ null,
242
+ {
243
+ "json_class": "Range",
244
+ "data": [
245
+ 4,
246
+ 10,
247
+ false
248
+ ]
249
+ }
250
+ ]
251
+ ```
252
+
253
+ There are also the methods `Kernel#j` for generate, and `Kernel#jj` for
254
+ `pretty_generate` output to the console, that work analogous to Core Ruby's `p` and
255
+ the `pp` library's `pp` methods.
256
+
257
+ The script `tools/server.rb` contains a small example if you want to test, how
258
+ receiving a JSON object from a webrick server in your browser with the
259
+ JavaScript prototype library http://www.prototypejs.org works.
260
+
261
+ ## Speed Comparisons
262
+
263
+ I have created some benchmark results (see the benchmarks/data-p4-3Ghz
264
+ subdir of the package) for the JSON-parser to estimate the speed up in the C
265
+ extension:
266
+
267
+ ```
268
+ Comparing times (call_time_mean):
269
+ 1 ParserBenchmarkExt#parser 900 repeats:
270
+ 553.922304770 ( real) -> 21.500x
271
+ 0.001805307
272
+ 2 ParserBenchmarkYAML#parser 1000 repeats:
273
+ 224.513358139 ( real) -> 8.714x
274
+ 0.004454078
275
+ 3 ParserBenchmarkPure#parser 1000 repeats:
276
+ 26.755020642 ( real) -> 1.038x
277
+ 0.037376163
278
+ 4 ParserBenchmarkRails#parser 1000 repeats:
279
+ 25.763381731 ( real) -> 1.000x
280
+ 0.038814780
281
+ calls/sec ( time) -> speed covers
282
+ secs/call
283
+ ```
284
+
285
+ In the table above 1 is `JSON::Ext::Parser`, 2 is `YAML.load` with YAML
286
+ compatible JSON document, 3 is is `JSON::Pure::Parser`, and 4 is
287
+ `ActiveSupport::JSON.decode`. The ActiveSupport JSON-decoder converts the
288
+ input first to YAML and then uses the YAML-parser, the conversion seems to
289
+ slow it down so much that it is only as fast as the `JSON::Pure::Parser`!
290
+
291
+ If you look at the benchmark data you can see that this is mostly caused by
292
+ the frequent high outliers - the median of the Rails-parser runs is still
293
+ overall smaller than the median of the `JSON::Pure::Parser` runs:
294
+
295
+ ```
296
+ Comparing times (call_time_median):
297
+ 1 ParserBenchmarkExt#parser 900 repeats:
298
+ 800.592479481 ( real) -> 26.936x
299
+ 0.001249075
300
+ 2 ParserBenchmarkYAML#parser 1000 repeats:
301
+ 271.002390644 ( real) -> 9.118x
302
+ 0.003690004
303
+ 3 ParserBenchmarkRails#parser 1000 repeats:
304
+ 30.227910865 ( real) -> 1.017x
305
+ 0.033082008
306
+ 4 ParserBenchmarkPure#parser 1000 repeats:
307
+ 29.722384421 ( real) -> 1.000x
308
+ 0.033644676
309
+ calls/sec ( time) -> speed covers
310
+ secs/call
311
+ ```
312
+
313
+ I have benchmarked the `JSON-Generator` as well. This generated a few more
314
+ values, because there are different modes that also influence the achieved
315
+ speed:
316
+
317
+ ```
318
+ Comparing times (call_time_mean):
319
+ 1 GeneratorBenchmarkExt#generator_fast 1000 repeats:
320
+ 547.354332608 ( real) -> 15.090x
321
+ 0.001826970
322
+ 2 GeneratorBenchmarkExt#generator_safe 1000 repeats:
323
+ 443.968212317 ( real) -> 12.240x
324
+ 0.002252414
325
+ 3 GeneratorBenchmarkExt#generator_pretty 900 repeats:
326
+ 375.104545883 ( real) -> 10.341x
327
+ 0.002665923
328
+ 4 GeneratorBenchmarkPure#generator_fast 1000 repeats:
329
+ 49.978706968 ( real) -> 1.378x
330
+ 0.020008521
331
+ 5 GeneratorBenchmarkRails#generator 1000 repeats:
332
+ 38.531868759 ( real) -> 1.062x
333
+ 0.025952543
334
+ 6 GeneratorBenchmarkPure#generator_safe 1000 repeats:
335
+ 36.927649925 ( real) -> 1.018x 7 (>=3859)
336
+ 0.027079979
337
+ 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats:
338
+ 36.272134441 ( real) -> 1.000x 6 (>=3859)
339
+ 0.027569373
340
+ calls/sec ( time) -> speed covers
341
+ secs/call
342
+ ```
343
+
344
+ In the table above 1-3 are `JSON::Ext::Generator` methods. 4, 6, and 7 are
345
+ `JSON::Pure::Generator` methods and 5 is the Rails JSON generator. It is now a
346
+ bit faster than the `generator_safe` and `generator_pretty` methods of the pure
347
+ variant but slower than the others.
348
+
349
+ To achieve the fastest JSON document output, you can use the `fast_generate`
350
+ method. Beware, that this will disable the checking for circular Ruby data
351
+ structures, which may cause JSON to go into an infinite loop.
352
+
353
+ Here are the median comparisons for completeness' sake:
354
+
355
+ ```
356
+ Comparing times (call_time_median):
357
+ 1 GeneratorBenchmarkExt#generator_fast 1000 repeats:
358
+ 708.258020939 ( real) -> 16.547x
359
+ 0.001411915
360
+ 2 GeneratorBenchmarkExt#generator_safe 1000 repeats:
361
+ 569.105020353 ( real) -> 13.296x
362
+ 0.001757145
363
+ 3 GeneratorBenchmarkExt#generator_pretty 900 repeats:
364
+ 482.825371244 ( real) -> 11.280x
365
+ 0.002071142
366
+ 4 GeneratorBenchmarkPure#generator_fast 1000 repeats:
367
+ 62.717626652 ( real) -> 1.465x
368
+ 0.015944481
369
+ 5 GeneratorBenchmarkRails#generator 1000 repeats:
370
+ 43.965681162 ( real) -> 1.027x
371
+ 0.022745013
372
+ 6 GeneratorBenchmarkPure#generator_safe 1000 repeats:
373
+ 43.929073409 ( real) -> 1.026x 7 (>=3859)
374
+ 0.022763968
375
+ 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats:
376
+ 42.802514491 ( real) -> 1.000x 6 (>=3859)
377
+ 0.023363113
378
+ calls/sec ( time) -> speed covers
379
+ secs/call
380
+ ```
381
+
382
+ ## Development
383
+
384
+ ### Release
385
+
386
+ Update the json.gemspec and json-java.gemspec.
387
+
388
+ ```
389
+ rbenv shell 2.6.5
390
+ rake build
391
+ gem push pkg/json-2.3.0.gem
392
+
393
+ rbenv shell jruby-9.2.9.0
394
+ rake build
395
+ gem push pkg/json-2.3.0-java.gem
396
+ ```
397
+
398
+ ## Author
399
+
400
+ Florian Frank <mailto:flori@ping.de>
401
+
402
+ ## License
403
+
404
+ Ruby License, see https://www.ruby-lang.org/en/about/license.txt.
405
+
406
+ ## Download
407
+
408
+ The latest version of this library can be downloaded at
409
+
410
+ * https://rubygems.org/gems/json
411
+
412
+ Online Documentation should be located at
413
+
414
+ * https://www.rubydoc.info/gems/json
415
+
416
+ [Ragel]: http://www.colm.net/open-source/ragel/
@@ -0,0 +1,187 @@
1
+
2
+ #ifndef _FBUFFER_H_
3
+ #define _FBUFFER_H_
4
+
5
+ #include "ruby.h"
6
+
7
+ #ifndef RHASH_SIZE
8
+ #define RHASH_SIZE(hsh) (RHASH(hsh)->tbl->num_entries)
9
+ #endif
10
+
11
+ #ifndef RFLOAT_VALUE
12
+ #define RFLOAT_VALUE(val) (RFLOAT(val)->value)
13
+ #endif
14
+
15
+ #ifndef RARRAY_LEN
16
+ #define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
17
+ #endif
18
+ #ifndef RSTRING_PTR
19
+ #define RSTRING_PTR(string) RSTRING(string)->ptr
20
+ #endif
21
+ #ifndef RSTRING_LEN
22
+ #define RSTRING_LEN(string) RSTRING(string)->len
23
+ #endif
24
+
25
+ #ifdef PRIsVALUE
26
+ # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
27
+ # define RB_OBJ_STRING(obj) (obj)
28
+ #else
29
+ # define PRIsVALUE "s"
30
+ # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
31
+ # define RB_OBJ_STRING(obj) StringValueCStr(obj)
32
+ #endif
33
+
34
+ #ifdef HAVE_RUBY_ENCODING_H
35
+ #include "ruby/encoding.h"
36
+ #define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
37
+ #else
38
+ #define FORCE_UTF8(obj)
39
+ #endif
40
+
41
+ /* We don't need to guard objects for rbx, so let's do nothing at all. */
42
+ #ifndef RB_GC_GUARD
43
+ #define RB_GC_GUARD(object)
44
+ #endif
45
+
46
+ typedef struct FBufferStruct {
47
+ unsigned long initial_length;
48
+ char *ptr;
49
+ unsigned long len;
50
+ unsigned long capa;
51
+ } FBuffer;
52
+
53
+ #define FBUFFER_INITIAL_LENGTH_DEFAULT 1024
54
+
55
+ #define FBUFFER_PTR(fb) (fb->ptr)
56
+ #define FBUFFER_LEN(fb) (fb->len)
57
+ #define FBUFFER_CAPA(fb) (fb->capa)
58
+ #define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb)
59
+
60
+ static FBuffer *fbuffer_alloc(unsigned long initial_length);
61
+ static void fbuffer_free(FBuffer *fb);
62
+ static void fbuffer_clear(FBuffer *fb);
63
+ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
64
+ #ifdef JSON_GENERATOR
65
+ static void fbuffer_append_long(FBuffer *fb, long number);
66
+ #endif
67
+ static void fbuffer_append_char(FBuffer *fb, char newchr);
68
+ #ifdef JSON_GENERATOR
69
+ static FBuffer *fbuffer_dup(FBuffer *fb);
70
+ static VALUE fbuffer_to_s(FBuffer *fb);
71
+ #endif
72
+
73
+ static FBuffer *fbuffer_alloc(unsigned long initial_length)
74
+ {
75
+ FBuffer *fb;
76
+ if (initial_length <= 0) initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
77
+ fb = ALLOC(FBuffer);
78
+ memset((void *) fb, 0, sizeof(FBuffer));
79
+ fb->initial_length = initial_length;
80
+ return fb;
81
+ }
82
+
83
+ static void fbuffer_free(FBuffer *fb)
84
+ {
85
+ if (fb->ptr) ruby_xfree(fb->ptr);
86
+ ruby_xfree(fb);
87
+ }
88
+
89
+ static void fbuffer_clear(FBuffer *fb)
90
+ {
91
+ fb->len = 0;
92
+ }
93
+
94
+ static void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
95
+ {
96
+ unsigned long required;
97
+
98
+ if (!fb->ptr) {
99
+ fb->ptr = ALLOC_N(char, fb->initial_length);
100
+ fb->capa = fb->initial_length;
101
+ }
102
+
103
+ for (required = fb->capa; requested > required - fb->len; required <<= 1);
104
+
105
+ if (required > fb->capa) {
106
+ REALLOC_N(fb->ptr, char, required);
107
+ fb->capa = required;
108
+ }
109
+ }
110
+
111
+ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
112
+ {
113
+ if (len > 0) {
114
+ fbuffer_inc_capa(fb, len);
115
+ MEMCPY(fb->ptr + fb->len, newstr, char, len);
116
+ fb->len += len;
117
+ }
118
+ }
119
+
120
+ #ifdef JSON_GENERATOR
121
+ static void fbuffer_append_str(FBuffer *fb, VALUE str)
122
+ {
123
+ const char *newstr = StringValuePtr(str);
124
+ unsigned long len = RSTRING_LEN(str);
125
+
126
+ RB_GC_GUARD(str);
127
+
128
+ fbuffer_append(fb, newstr, len);
129
+ }
130
+ #endif
131
+
132
+ static void fbuffer_append_char(FBuffer *fb, char newchr)
133
+ {
134
+ fbuffer_inc_capa(fb, 1);
135
+ *(fb->ptr + fb->len) = newchr;
136
+ fb->len++;
137
+ }
138
+
139
+ #ifdef JSON_GENERATOR
140
+ static void freverse(char *start, char *end)
141
+ {
142
+ char c;
143
+
144
+ while (end > start) {
145
+ c = *end, *end-- = *start, *start++ = c;
146
+ }
147
+ }
148
+
149
+ static long fltoa(long number, char *buf)
150
+ {
151
+ static char digits[] = "0123456789";
152
+ long sign = number;
153
+ char* tmp = buf;
154
+
155
+ if (sign < 0) number = -number;
156
+ do *tmp++ = digits[number % 10]; while (number /= 10);
157
+ if (sign < 0) *tmp++ = '-';
158
+ freverse(buf, tmp - 1);
159
+ return tmp - buf;
160
+ }
161
+
162
+ static void fbuffer_append_long(FBuffer *fb, long number)
163
+ {
164
+ char buf[20];
165
+ unsigned long len = fltoa(number, buf);
166
+ fbuffer_append(fb, buf, len);
167
+ }
168
+
169
+ static FBuffer *fbuffer_dup(FBuffer *fb)
170
+ {
171
+ unsigned long len = fb->len;
172
+ FBuffer *result;
173
+
174
+ result = fbuffer_alloc(len);
175
+ fbuffer_append(result, FBUFFER_PAIR(fb));
176
+ return result;
177
+ }
178
+
179
+ static VALUE fbuffer_to_s(FBuffer *fb)
180
+ {
181
+ VALUE result = rb_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
182
+ fbuffer_free(fb);
183
+ FORCE_UTF8(result);
184
+ return result;
185
+ }
186
+ #endif
187
+ #endif
@@ -0,0 +1 @@
1
+ generator.o: generator.c generator.h $(srcdir)/../fbuffer/fbuffer.h
@@ -1,9 +1,4 @@
1
1
  require 'mkmf'
2
- require 'rbconfig'
3
2
 
4
- if CONFIG['CC'] =~ /gcc/
5
- CONFIG['CC'] += ' -Wall -ggdb'
6
- #CONFIG['CC'] += ' -Wall'
7
- end
8
-
9
- create_makefile 'generator'
3
+ $defs << "-DJSON_GENERATOR"
4
+ create_makefile 'json/ext/generator'