summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Frank <flori@ping.de>2009-11-20 08:25:28 +0100
committerFlorian Frank <flori@ping.de>2009-11-20 08:25:28 +0100
commit64c9ee30094d02a257eaeb9306e15ed5bdf7f982 (patch)
treea0da7726b257f0114c4b6193ea81d19fa2024479
parent5a28815043c4ab7aa3c45485f4f0f363b54f95b0 (diff)
downloadjson-64c9ee30094d02a257eaeb9306e15ed5bdf7f982.tar.gz
implemented prototype feature
-rw-r--r--ext/json/ext/generator.c57
-rw-r--r--ext/json/ext/generator.h1
-rw-r--r--lib/json/common.rb56
-rw-r--r--lib/json/pure/generator.rb12
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