diff options
author | Florian Frank <flori@ping.de> | 2009-11-20 08:25:28 +0100 |
---|---|---|
committer | Florian Frank <flori@ping.de> | 2009-11-20 08:25:28 +0100 |
commit | 64c9ee30094d02a257eaeb9306e15ed5bdf7f982 (patch) | |
tree | a0da7726b257f0114c4b6193ea81d19fa2024479 | |
parent | 5a28815043c4ab7aa3c45485f4f0f363b54f95b0 (diff) | |
download | json-64c9ee30094d02a257eaeb9306e15ed5bdf7f982.tar.gz |
implemented prototype feature
-rw-r--r-- | ext/json/ext/generator.c | 57 | ||||
-rw-r--r-- | ext/json/ext/generator.h | 1 | ||||
-rw-r--r-- | lib/json/common.rb | 56 | ||||
-rw-r--r-- | lib/json/pure/generator.rb | 12 |
4 files changed, 92 insertions, 34 deletions
diff --git a/ext/json/ext/generator.c b/ext/json/ext/generator.c index e07a7af..bb187a1 100644 --- a/ext/json/ext/generator.c +++ b/ext/json/ext/generator.c @@ -8,7 +8,7 @@ static ID i_encoding, i_encode; static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject, mHash, mArray, mInteger, mFloat, mString, mString_Extend, mTrueClass, mFalseClass, mNilClass, eGeneratorError, - eNestingError, CRegexp_MULTILINE; + eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE; static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before, i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only, @@ -346,7 +346,7 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned int len) { if (len > 0) { fbuffer_inc_capa(fb, len); - memcpy(fb->ptr + fb->len, newstr, len); + MEMCPY(fb->ptr + fb->len, newstr, char, len); fb->len += len; } } @@ -358,6 +358,20 @@ static void fbuffer_append_char(FBuffer *fb, char newchr) fb->len++; } +static FBuffer *fbuffer_dup(FBuffer *fb) +{ + int len = fb->len; + FBuffer *result; + + if (len > 0) { + result = fbuffer_alloc_with_length(len); + fbuffer_append(result, FBUFFER_PAIR(fb)); + } else { + result = fbuffer_alloc(); + } + return result; +} + /* * Document-module: JSON::Ext::Generator * @@ -659,11 +673,11 @@ static VALUE cState_to_h(VALUE self) { VALUE result = rb_hash_new(); GET_STATE(self); - rb_hash_aset(result, ID2SYM(i_indent), rb_str_new2(state->indent)); - rb_hash_aset(result, ID2SYM(i_space), rb_str_new2(state->space)); - rb_hash_aset(result, ID2SYM(i_space_before), rb_str_new2(state->space_before)); - rb_hash_aset(result, ID2SYM(i_object_nl), rb_str_new2(state->object_nl)); - rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new2(state->array_nl)); + rb_hash_aset(result, ID2SYM(i_indent), rb_str_new(state->indent, state->indent_len)); + rb_hash_aset(result, ID2SYM(i_space), rb_str_new(state->space, state->space_len)); + rb_hash_aset(result, ID2SYM(i_space_before), rb_str_new(state->space_before, state->space_before_len)); + rb_hash_aset(result, ID2SYM(i_object_nl), rb_str_new(state->object_nl, state->object_nl_len)); + rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len)); rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse); rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse); rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting)); @@ -951,6 +965,28 @@ static VALUE cState_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* XXX +*/ +static VALUE cState_init_copy(VALUE obj, VALUE orig) +{ + JSON_Generator_State *objState, *origState; + + Data_Get_Struct(obj, JSON_Generator_State, objState); + Data_Get_Struct(orig, JSON_Generator_State, origState); + if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State"); + + MEMCPY(objState, origState, JSON_Generator_State, 1); + objState->indent = fstrndup(origState->indent, origState->indent_len); + objState->space = fstrndup(origState->space, origState->space_len); + objState->space_before = fstrndup(origState->space_before, origState->space_before_len); + objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len); + objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len); + if (origState->array_delim) objState->array_delim = fbuffer_dup(origState->array_delim); + if (origState->object_delim) objState->object_delim = fbuffer_dup(origState->object_delim); + if (origState->object_delim2) objState->object_delim2 = fbuffer_dup(origState->object_delim2); + return obj; +} + /* * call-seq: from_state(opts) * @@ -965,7 +1001,10 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts) } else if (rb_obj_is_kind_of(opts, rb_cHash)) { return rb_funcall(self, i_new, 1, opts); } else { - return rb_funcall(self, i_new, 0); + if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) { + CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, rb_intern("SAFE_STATE_PROTOTYPE")); + } + return CJSON_SAFE_STATE_PROTOTYPE; } } @@ -1200,6 +1239,7 @@ void Init_generator() rb_define_alloc_func(cState, cState_s_allocate); rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1); rb_define_method(cState, "initialize", cState_initialize, -1); + rb_define_method(cState, "initialize_copy", cState_init_copy, 1); rb_define_method(cState, "indent", cState_indent, 0); rb_define_method(cState, "indent=", cState_indent_set, 1); rb_define_method(cState, "space", cState_space, 0); @@ -1265,4 +1305,5 @@ void Init_generator() i_encoding = rb_intern("encoding"); i_encode = rb_intern("encode"); #endif + CJSON_SAFE_STATE_PROTOTYPE = Qnil; } diff --git a/ext/json/ext/generator.h b/ext/json/ext/generator.h index c466402..664d108 100644 --- a/ext/json/ext/generator.h +++ b/ext/json/ext/generator.h @@ -81,6 +81,7 @@ static void fbuffer_free_only_buffer(FBuffer *fb); static void fbuffer_clear(FBuffer *fb); static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned int len); static void fbuffer_append_char(FBuffer *fb, char newchr); +static FBuffer *fbuffer_dup(FBuffer *fb); /* unicode defintions */ diff --git a/lib/json/common.rb b/lib/json/common.rb index 5c10071..c0b35e2 100644 --- a/lib/json/common.rb +++ b/lib/json/common.rb @@ -59,6 +59,20 @@ module JSON end self.state = generator::State const_set :State, self.state + const_set :SAFE_STATE_PROTOTYPE, State.new.freeze + const_set :FAST_STATE_PROTOTYPE, State.new( + :indent => '', + :space => '', + :object_nl => "", + :array_nl => "", + :max_nesting => false + ).freeze + const_set :PRETTY_STATE_PROTOTYPE, State.new( + :indent => ' ', + :space => ' ', + :object_nl => "\n", + :array_nl => "\n" + ).freeze end # Returns the JSON generator modul, that is used by JSON. This might be @@ -120,7 +134,7 @@ module JSON # additions even if a matchin class and create_id was found. This option # defaults to true. def parse(source, opts = {}) - JSON.parser.new(source, opts).parse + Parser.new(source, opts).parse end # Parse the JSON document _source_ into a Ruby data structure and return it. @@ -140,10 +154,10 @@ module JSON # defaults to true. def parse!(source, opts = {}) opts = { - :max_nesting => false, - :allow_nan => true + :max_nesting => false, + :allow_nan => true }.update(opts) - JSON.parser.new(source, opts).parse + Parser.new(source, opts).parse end # Generate a JSON document from the Ruby data structure _obj_ and return @@ -172,11 +186,19 @@ module JSON # See also the fast_generate for the fastest creation method with the least # amount of sanity checks, and the pretty_generate method for some # defaults for a pretty output. - def generate(obj, state = nil) - if state - state = State.from_state(state) + def generate(obj, opts = nil) + if opts + if opts.respond_to? :to_hash + opts = opts.to_hash + elsif opts.respond_to? :to_h + opts = opts.to_h + else + raise TypeError, "can't convert #{opts.class} into Hash" + end + state = SAFE_STATE_PROTOTYPE.dup + state = state.configure(opts) else - state = State.new + state = SAFE_STATE_PROTOTYPE end state.generate(obj) end @@ -194,12 +216,6 @@ module JSON # *WARNING*: Be careful not to pass any Ruby data structures with circles as # _obj_ argument, because this will cause JSON to go into an infinite loop. def fast_generate(obj, opts = nil) - state = JSON.state.new( - :indent => '', - :space => '', - :object_nl => "", - :array_nl => "" - ) if opts if opts.respond_to? :to_hash opts = opts.to_hash @@ -208,7 +224,10 @@ module JSON else raise TypeError, "can't convert #{opts.class} into Hash" end + state = FAST_STATE_PROTOTYPE.dup state.configure(opts) + else + state = FAST_STATE_PROTOTYPE end state.generate(obj) end @@ -226,12 +245,6 @@ module JSON # The _opts_ argument can be used to configure the generator, see the # generate method for a more detailed explanation. def pretty_generate(obj, opts = nil) - state = JSON.state.new( - :indent => ' ', - :space => ' ', - :object_nl => "\n", - :array_nl => "\n" - ) if opts if opts.respond_to? :to_hash opts = opts.to_hash @@ -240,7 +253,10 @@ module JSON else raise TypeError, "can't convert #{opts.class} into Hash" end + state = PRETTY_STATE_PROTOTYPE.dup state.configure(opts) + else + state = PRETTY_STATE_PROTOTYPE end state.generate(obj) end diff --git a/lib/json/pure/generator.rb b/lib/json/pure/generator.rb index 256bdb5..a656768 100644 --- a/lib/json/pure/generator.rb +++ b/lib/json/pure/generator.rb @@ -112,7 +112,7 @@ module JSON when Hash new(opts) else - new + SAFE_STATE_PROTOTYPE end end @@ -210,7 +210,7 @@ module JSON # passed to the configure method. def to_h result = {} - for iv in %w[indent space space_before object_nl array_nl check_circular allow_nan max_nesting] + for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting] result[iv.intern] = instance_variable_get("@#{iv}") end result @@ -244,7 +244,7 @@ module JSON # _depth_ is used to find out nesting depth, to indent accordingly. def to_json(state = nil, depth = 0, *) if state - state = JSON.state.from_state(state) + state = State.from_state(state) state.check_max_nesting(depth) end json_transform(state, depth) @@ -299,7 +299,7 @@ module JSON # _depth_ is used to find out nesting depth, to indent accordingly. def to_json(state = nil, depth = 0, *) if state - state = JSON.state.from_state(state) + state = State.from_state(state) state.check_max_nesting(depth) end json_transform(state, depth) @@ -366,7 +366,7 @@ module JSON # \u????. def to_json(*args) state, = *args - state ||= JSON.state.from_state(state) + state ||= State.from_state(state) if encoding == ::Encoding::UTF_8 string = self else @@ -384,7 +384,7 @@ module JSON # \u????. def to_json(*args) state, = *args - state ||= JSON.state.from_state(state) + state ||= State.from_state(state) if state.ascii_only? '"' << JSON.utf8_to_json_ascii(self) << '"' else |