ffi-yajl 2.7.5-universal-mingw-ucrt
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +118 -0
- data/bin/ffi-yajl-bench +36 -0
- data/ext/ffi_yajl/ext/dlopen/dlopen.c +40 -0
- data/ext/ffi_yajl/ext/dlopen/extconf.rb +16 -0
- data/ext/ffi_yajl/ext/dlopen/yajl.sym +18 -0
- data/ext/ffi_yajl/ext/encoder/encoder.c +395 -0
- data/ext/ffi_yajl/ext/encoder/extconf.rb +86 -0
- data/ext/ffi_yajl/ext/parser/extconf.rb +86 -0
- data/ext/ffi_yajl/ext/parser/parser.c +240 -0
- data/lib/ffi_yajl/benchmark/MIT-LICENSE +20 -0
- data/lib/ffi_yajl/benchmark/encode.rb +82 -0
- data/lib/ffi_yajl/benchmark/encode_json_and_marshal.rb +42 -0
- data/lib/ffi_yajl/benchmark/encode_json_and_yaml.rb +47 -0
- data/lib/ffi_yajl/benchmark/encode_profile.rb +34 -0
- data/lib/ffi_yajl/benchmark/http.rb +28 -0
- data/lib/ffi_yajl/benchmark/parse.rb +93 -0
- data/lib/ffi_yajl/benchmark/parse_json_and_marshal.rb +50 -0
- data/lib/ffi_yajl/benchmark/parse_json_and_yaml.rb +55 -0
- data/lib/ffi_yajl/benchmark/parse_profile.rb +33 -0
- data/lib/ffi_yajl/benchmark/parse_profile_ruby_prof.rb +34 -0
- data/lib/ffi_yajl/benchmark/parse_stream.rb +54 -0
- data/lib/ffi_yajl/benchmark/subjects/item.json +1 -0
- data/lib/ffi_yajl/benchmark/subjects/ohai.json +1216 -0
- data/lib/ffi_yajl/benchmark/subjects/ohai.marshal_dump +0 -0
- data/lib/ffi_yajl/benchmark/subjects/ohai.yml +975 -0
- data/lib/ffi_yajl/benchmark/subjects/twitter_search.json +1 -0
- data/lib/ffi_yajl/benchmark/subjects/twitter_stream.json +430 -0
- data/lib/ffi_yajl/benchmark/subjects/unicode.json +1 -0
- data/lib/ffi_yajl/benchmark.rb +27 -0
- data/lib/ffi_yajl/encoder.rb +94 -0
- data/lib/ffi_yajl/ext/.keep +0 -0
- data/lib/ffi_yajl/ext.rb +49 -0
- data/lib/ffi_yajl/ffi/encoder.rb +262 -0
- data/lib/ffi_yajl/ffi/parser.rb +163 -0
- data/lib/ffi_yajl/ffi.rb +153 -0
- data/lib/ffi_yajl/map_library_name.rb +109 -0
- data/lib/ffi_yajl/parser.rb +91 -0
- data/lib/ffi_yajl/platform.rb +29 -0
- data/lib/ffi_yajl/version.rb +25 -0
- data/lib/ffi_yajl.rb +50 -0
- metadata +128 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# rubocop:disable Style/GlobalVars
|
|
2
|
+
require "mkmf"
|
|
3
|
+
require "rubygems"
|
|
4
|
+
require "libyajl2"
|
|
5
|
+
|
|
6
|
+
RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] if ENV["CC"]
|
|
7
|
+
|
|
8
|
+
# pick up the vendored libyajl2 out of the libyajl2 gem
|
|
9
|
+
$CFLAGS = " -I#{Libyajl2.include_path} #{$CFLAGS}"
|
|
10
|
+
$LDFLAGS = " -L#{Libyajl2.opt_path} #{$LDFLAGS}"
|
|
11
|
+
|
|
12
|
+
# remove "-Wl,--no-undefined" flag if existent to allow for loading with dlopen
|
|
13
|
+
$LDFLAGS.slice!("-Wl,--no-undefined")
|
|
14
|
+
|
|
15
|
+
puts $CFLAGS
|
|
16
|
+
puts $LDFLAGS
|
|
17
|
+
|
|
18
|
+
# except if you're doing an unoptimized gcc install we're going to help you out a bit
|
|
19
|
+
if RbConfig::MAKEFILE_CONFIG["CC"] =~ /gcc|clang/
|
|
20
|
+
$CFLAGS << " -O3" unless $CFLAGS[/-O\d/]
|
|
21
|
+
# how many people realize that -Wall is a compiler-specific flag???
|
|
22
|
+
# apparently not many based on reading lots of shitty extconf.rb's out there
|
|
23
|
+
$CFLAGS << " -Wall"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def windows?
|
|
27
|
+
!!(RUBY_PLATFORM =~ /mswin|mingw|cygwin|windows/)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def macos?
|
|
31
|
+
!!(RUBY_PLATFORM =~ /darwin/)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def clang?
|
|
35
|
+
cc_version = `#{RbConfig.expand("$(CC) --version")}`
|
|
36
|
+
cc_version.match?(/clang/i)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# XCode 14 warns if `-Wl,-undefined dynamic_lookup` is specified, and as
|
|
40
|
+
# a result Ruby interpreters compiled under XCode 14 no longer specify
|
|
41
|
+
# this flag by default in DLDFLAGS. Let's specify the list of dynamic symbols
|
|
42
|
+
# here to avoid compilation failures.
|
|
43
|
+
if clang? && macos?
|
|
44
|
+
symfile = File.join(__dir__, "../dlopen/yajl.sym")
|
|
45
|
+
dynamic_symbols = File.readlines(symfile)
|
|
46
|
+
dynamic_symbols.each do |sym|
|
|
47
|
+
$DLDFLAGS << " -Wl,-U,#{sym.strip}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if windows?
|
|
52
|
+
# include our libyajldll.a definitions on windows in the libyajl2 gem
|
|
53
|
+
$libs = "#{$libs} -lyajldll"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# NOTE: find_library has the side effect of adding -lyajl to the flags which we are deliberately
|
|
57
|
+
# avoiding doing with the libyajl2-gem (allowing it to be lazily loaded with dlopen)
|
|
58
|
+
if !windows? && !find_header("yajl/yajl_tree.h")
|
|
59
|
+
puts "libyajl2 headers not found in libyajl2-gem, searching for system libraries..."
|
|
60
|
+
|
|
61
|
+
HEADER_DIRS = [
|
|
62
|
+
"/opt/local/include", # MacPorts
|
|
63
|
+
"/usr/local/include", # /usr/local
|
|
64
|
+
RbConfig::CONFIG["includedir"], # Ruby
|
|
65
|
+
"/usr/include", # (default)
|
|
66
|
+
].freeze
|
|
67
|
+
|
|
68
|
+
LIB_DIRS = [
|
|
69
|
+
"/opt/local/lib", # MacPorts
|
|
70
|
+
"/usr/local/lib", # /usr/local + Homebrew
|
|
71
|
+
RbConfig::CONFIG["libdir"], # Ruby
|
|
72
|
+
"/usr/lib", # (default)
|
|
73
|
+
].freeze
|
|
74
|
+
|
|
75
|
+
# add --with-yajl-dir, --with-yajl-include, --with-yajl-lib
|
|
76
|
+
dir_config("yajl", HEADER_DIRS, LIB_DIRS)
|
|
77
|
+
|
|
78
|
+
# here we use find_library in order to deliberately link with -lyajl as a useful side-effect
|
|
79
|
+
unless find_header("yajl/yajl_tree.h") && find_library("yajl", "yajl_complete_parse")
|
|
80
|
+
abort "libyajl2 is missing. please install libyajl2"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
dir_config "encoder"
|
|
85
|
+
|
|
86
|
+
create_makefile "ffi_yajl/ext/encoder"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# rubocop:disable Style/GlobalVars
|
|
2
|
+
require "mkmf"
|
|
3
|
+
require "rubygems"
|
|
4
|
+
require "libyajl2"
|
|
5
|
+
|
|
6
|
+
RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] if ENV["CC"]
|
|
7
|
+
|
|
8
|
+
# pick up the vendored libyajl2 out of the libyajl2 gem
|
|
9
|
+
$CFLAGS = "-I#{Libyajl2.include_path} #{$CFLAGS}"
|
|
10
|
+
$LDFLAGS = "-L#{Libyajl2.opt_path} #{$LDFLAGS}"
|
|
11
|
+
|
|
12
|
+
# remove "-Wl,--no-undefined" flag if existent to allow for loading with dlopen
|
|
13
|
+
$LDFLAGS.slice!("-Wl,--no-undefined")
|
|
14
|
+
|
|
15
|
+
puts $CFLAGS
|
|
16
|
+
puts $LDFLAGS
|
|
17
|
+
|
|
18
|
+
# except if you're doing an unoptimized gcc install we're going to help you out a bit
|
|
19
|
+
if RbConfig::MAKEFILE_CONFIG["CC"] =~ /gcc|clang/
|
|
20
|
+
$CFLAGS << " -O3" unless $CFLAGS[/-O\d/]
|
|
21
|
+
# how many people realize that -Wall is a compiler-specific flag???
|
|
22
|
+
# apparently not many based on reading lots of shitty extconf.rb's out there
|
|
23
|
+
$CFLAGS << " -Wall"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def windows?
|
|
27
|
+
!!(RUBY_PLATFORM =~ /mswin|mingw|cygwin|windows/)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def macos?
|
|
31
|
+
!!(RUBY_PLATFORM =~ /darwin/)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def clang?
|
|
35
|
+
cc_version = `#{RbConfig.expand("$(CC) --version")}`
|
|
36
|
+
cc_version.match?(/clang/i)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# XCode 14 warns if `-Wl,-undefined dynamic_lookup` is specified, and as
|
|
40
|
+
# a result Ruby interpreters compiled under XCode 14 no longer specify
|
|
41
|
+
# this flag by default in DLDFLAGS. Let's specify the list of dynamic symbols
|
|
42
|
+
# here to avoid compilation failures.
|
|
43
|
+
if clang? && macos?
|
|
44
|
+
symfile = File.join(__dir__, "../dlopen/yajl.sym")
|
|
45
|
+
dynamic_symbols = File.readlines(symfile)
|
|
46
|
+
dynamic_symbols.each do |sym|
|
|
47
|
+
$DLDFLAGS << " -Wl,-U,#{sym.strip}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if windows?
|
|
52
|
+
# include our libyajldll.a definitions on windows in the libyajl2 gem
|
|
53
|
+
$libs = "#{$libs} -lyajldll"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# NOTE: find_library has the side effect of adding -lyajl to the flags which we are deliberately
|
|
57
|
+
# avoiding doing with the libyajl2-gem (allowing it to be lazily loaded with dlopen)
|
|
58
|
+
if !windows? && !find_header("yajl/yajl_tree.h")
|
|
59
|
+
puts "libyajl2 headers not found in libyajl2-gem, searching for system libraries..."
|
|
60
|
+
|
|
61
|
+
HEADER_DIRS = [
|
|
62
|
+
"/opt/local/include", # MacPorts
|
|
63
|
+
"/usr/local/include", # /usr/local
|
|
64
|
+
RbConfig::CONFIG["includedir"], # Ruby
|
|
65
|
+
"/usr/include", # (default)
|
|
66
|
+
].freeze
|
|
67
|
+
|
|
68
|
+
LIB_DIRS = [
|
|
69
|
+
"/opt/local/lib", # MacPorts
|
|
70
|
+
"/usr/local/lib", # /usr/local + Homebrew
|
|
71
|
+
RbConfig::CONFIG["libdir"], # Ruby
|
|
72
|
+
"/usr/lib", # (default)
|
|
73
|
+
].freeze
|
|
74
|
+
|
|
75
|
+
# add --with-yajl-dir, --with-yajl-include, --with-yajl-lib
|
|
76
|
+
dir_config("yajl", HEADER_DIRS, LIB_DIRS)
|
|
77
|
+
|
|
78
|
+
# here we use find_library in order to deliberately link with -lyajl as a useful side-effect
|
|
79
|
+
unless find_header("yajl/yajl_tree.h") && find_library("yajl", "yajl_complete_parse")
|
|
80
|
+
abort "libyajl2 is missing. please install libyajl2"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
dir_config "parser"
|
|
85
|
+
|
|
86
|
+
create_makefile "ffi_yajl/ext/parser"
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include <yajl/yajl_parse.h>
|
|
3
|
+
|
|
4
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
5
|
+
#include <ruby/encoding.h>
|
|
6
|
+
static rb_encoding *utf8Encoding;
|
|
7
|
+
#endif
|
|
8
|
+
|
|
9
|
+
static VALUE mFFI_Yajl, mExt, mParser, cParseError;
|
|
10
|
+
|
|
11
|
+
typedef struct {
|
|
12
|
+
VALUE self;
|
|
13
|
+
int symbolizeKeys;
|
|
14
|
+
int uniqueKeyChecking;
|
|
15
|
+
} CTX;
|
|
16
|
+
|
|
17
|
+
void set_value(CTX *ctx, VALUE val) {
|
|
18
|
+
VALUE stack = rb_ivar_get(ctx->self, rb_intern("stack"));
|
|
19
|
+
VALUE key = rb_ivar_get(ctx->self, rb_intern("key"));
|
|
20
|
+
long len = RARRAY_LEN(stack);
|
|
21
|
+
VALUE last = rb_ary_entry(stack, len-1);
|
|
22
|
+
switch (TYPE(last)) {
|
|
23
|
+
case T_ARRAY:
|
|
24
|
+
rb_ary_push(last, val);
|
|
25
|
+
break;
|
|
26
|
+
case T_HASH:
|
|
27
|
+
if ( ctx->uniqueKeyChecking ) {
|
|
28
|
+
ID sym_has_key = rb_intern("has_key?");
|
|
29
|
+
if ( rb_funcall(last, sym_has_key, 1, key) == Qtrue ) {
|
|
30
|
+
rb_raise(cParseError, "repeated key: %s", RSTRING_PTR(key));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
rb_hash_aset(last, key, val);
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
rb_ary_push(stack, val);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
void set_key(CTX *ctx, VALUE key) {
|
|
42
|
+
rb_ivar_set(ctx->self, rb_intern("key"), key);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void start_object(CTX *ctx, VALUE obj) {
|
|
46
|
+
VALUE key_stack = rb_ivar_get(ctx->self, rb_intern("key_stack"));
|
|
47
|
+
VALUE key = rb_ivar_get(ctx->self, rb_intern("key"));
|
|
48
|
+
VALUE stack = rb_ivar_get(ctx->self, rb_intern("stack"));
|
|
49
|
+
|
|
50
|
+
rb_ary_push(key_stack, key);
|
|
51
|
+
rb_ary_push(stack, obj);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void end_object(CTX *ctx) {
|
|
55
|
+
VALUE key_stack = rb_ivar_get(ctx->self, rb_intern("key_stack"));
|
|
56
|
+
VALUE stack = rb_ivar_get(ctx->self, rb_intern("stack"));
|
|
57
|
+
rb_ivar_set(ctx->self, rb_intern("key"), rb_ary_pop(key_stack));
|
|
58
|
+
if ( RARRAY_LEN(stack) > 1 ) {
|
|
59
|
+
set_value(ctx, rb_ary_pop(stack));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
int null_callback(void *ctx) {
|
|
64
|
+
set_value(ctx, Qnil);
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
int boolean_callback(void *ctx, int boolean) {
|
|
69
|
+
set_value(ctx, boolean ? Qtrue : Qfalse);
|
|
70
|
+
return 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
int integer_callback(void *ctx, long long intVal) {
|
|
74
|
+
set_value(ctx, LONG2NUM(intVal));
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
int double_callback(void *ctx, double doubleVal) {
|
|
79
|
+
set_value(ctx, rb_float_new(doubleVal));
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
int number_callback(void *ctx, const char *numberVal, size_t numberLen) {
|
|
84
|
+
char *buf = (char *)malloc(numberLen+1);
|
|
85
|
+
buf[numberLen] = 0;
|
|
86
|
+
memcpy(buf, numberVal, numberLen);
|
|
87
|
+
if (memchr(buf, '.', numberLen) ||
|
|
88
|
+
memchr(buf, 'e', numberLen) ||
|
|
89
|
+
memchr(buf, 'E', numberLen)) {
|
|
90
|
+
set_value(ctx, rb_float_new(strtod(buf, NULL)));
|
|
91
|
+
} else {
|
|
92
|
+
set_value(ctx, rb_cstr2inum(buf, 10));
|
|
93
|
+
}
|
|
94
|
+
free(buf);
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
int string_callback(void *ctx, const unsigned char *stringVal, size_t stringLen) {
|
|
99
|
+
VALUE str = rb_str_new((const char *)stringVal, stringLen);
|
|
100
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
101
|
+
rb_encoding *default_internal_enc = rb_default_internal_encoding();
|
|
102
|
+
rb_enc_associate(str, utf8Encoding);
|
|
103
|
+
if (default_internal_enc) {
|
|
104
|
+
str = rb_str_export_to_enc(str, default_internal_enc);
|
|
105
|
+
}
|
|
106
|
+
#endif
|
|
107
|
+
set_value(ctx,str);
|
|
108
|
+
return 1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
int start_map_callback(void *ctx) {
|
|
112
|
+
start_object(ctx,rb_hash_new());
|
|
113
|
+
return 1;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
int map_key_callback(void *ctx, const unsigned char *stringVal, size_t stringLen) {
|
|
117
|
+
VALUE key;
|
|
118
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
119
|
+
rb_encoding *default_internal_enc;
|
|
120
|
+
#endif
|
|
121
|
+
|
|
122
|
+
if ( ((CTX *)ctx)->symbolizeKeys ) {
|
|
123
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
124
|
+
ID id = rb_intern3((const char *)stringVal, stringLen, utf8Encoding);
|
|
125
|
+
key = ID2SYM(id);
|
|
126
|
+
#else
|
|
127
|
+
VALUE str = rb_str_new((const char *)stringVal, stringLen);
|
|
128
|
+
key = rb_str_intern(str);
|
|
129
|
+
#endif
|
|
130
|
+
} else {
|
|
131
|
+
key = rb_str_new((const char *)stringVal, stringLen);
|
|
132
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
133
|
+
default_internal_enc = rb_default_internal_encoding();
|
|
134
|
+
rb_enc_associate(key, utf8Encoding);
|
|
135
|
+
if (default_internal_enc) {
|
|
136
|
+
key = rb_str_export_to_enc(key, default_internal_enc);
|
|
137
|
+
}
|
|
138
|
+
#endif
|
|
139
|
+
}
|
|
140
|
+
set_key(ctx, key);
|
|
141
|
+
return 1;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
int end_map_callback(void *ctx) {
|
|
145
|
+
end_object(ctx);
|
|
146
|
+
return 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
int start_array_callback(void *ctx) {
|
|
150
|
+
start_object(ctx,rb_ary_new());
|
|
151
|
+
return 1;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
int end_array_callback(void *ctx) {
|
|
155
|
+
end_object(ctx);
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static yajl_callbacks callbacks = {
|
|
160
|
+
null_callback,
|
|
161
|
+
boolean_callback,
|
|
162
|
+
integer_callback,
|
|
163
|
+
double_callback,
|
|
164
|
+
number_callback,
|
|
165
|
+
string_callback,
|
|
166
|
+
start_map_callback,
|
|
167
|
+
map_key_callback,
|
|
168
|
+
end_map_callback,
|
|
169
|
+
start_array_callback,
|
|
170
|
+
end_array_callback,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
int get_opts_key(VALUE self, const char *key) {
|
|
174
|
+
VALUE opts = rb_iv_get(self, "@opts");
|
|
175
|
+
if (TYPE(opts) != T_HASH) {
|
|
176
|
+
rb_raise(rb_eTypeError, "opts is not a valid hash");
|
|
177
|
+
}
|
|
178
|
+
return rb_hash_aref(opts, ID2SYM(rb_intern(key))) == Qtrue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static VALUE mParser_do_yajl_parse(VALUE self, VALUE str, VALUE yajl_opts) {
|
|
182
|
+
yajl_handle hand;
|
|
183
|
+
yajl_status stat;
|
|
184
|
+
unsigned char *err;
|
|
185
|
+
volatile CTX ctx;
|
|
186
|
+
|
|
187
|
+
rb_ivar_set(self, rb_intern("key"), Qnil);
|
|
188
|
+
rb_ivar_set(self, rb_intern("stack"), rb_ary_new());
|
|
189
|
+
rb_ivar_set(self, rb_intern("key_stack"), rb_ary_new());
|
|
190
|
+
|
|
191
|
+
ctx.self = self;
|
|
192
|
+
ctx.symbolizeKeys = get_opts_key(self, "symbolize_keys");
|
|
193
|
+
ctx.uniqueKeyChecking = get_opts_key(self, "unique_key_checking");
|
|
194
|
+
|
|
195
|
+
hand = yajl_alloc(&callbacks, NULL, (void *)&ctx);
|
|
196
|
+
|
|
197
|
+
if (rb_hash_aref(yajl_opts, ID2SYM(rb_intern("yajl_allow_comments"))) == Qtrue) {
|
|
198
|
+
yajl_config(hand, yajl_allow_comments, 1);
|
|
199
|
+
}
|
|
200
|
+
if (rb_hash_aref(yajl_opts, ID2SYM(rb_intern("yajl_dont_validate_strings"))) == Qtrue) {
|
|
201
|
+
yajl_config(hand, yajl_dont_validate_strings, 1);
|
|
202
|
+
}
|
|
203
|
+
if (rb_hash_aref(yajl_opts, ID2SYM(rb_intern("yajl_allow_trailing_garbage"))) == Qtrue) {
|
|
204
|
+
yajl_config(hand, yajl_allow_trailing_garbage, 1);
|
|
205
|
+
}
|
|
206
|
+
if (rb_hash_aref(yajl_opts, ID2SYM(rb_intern("yajl_allow_multiple_values"))) == Qtrue) {
|
|
207
|
+
yajl_config(hand, yajl_allow_multiple_values, 1);
|
|
208
|
+
}
|
|
209
|
+
if (rb_hash_aref(yajl_opts, ID2SYM(rb_intern("yajl_allow_partial_values"))) == Qtrue) {
|
|
210
|
+
yajl_config(hand, yajl_allow_partial_values, 1);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if ((stat = yajl_parse(hand, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str))) != yajl_status_ok) {
|
|
214
|
+
err = yajl_get_error(hand, 1, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
|
|
215
|
+
goto raise;
|
|
216
|
+
}
|
|
217
|
+
if ((stat = yajl_complete_parse(hand)) != yajl_status_ok) {
|
|
218
|
+
err = yajl_get_error(hand, 1, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
|
|
219
|
+
goto raise;
|
|
220
|
+
}
|
|
221
|
+
yajl_free(hand);
|
|
222
|
+
return rb_ary_pop(rb_ivar_get(self, rb_intern("stack")));
|
|
223
|
+
|
|
224
|
+
raise:
|
|
225
|
+
if (hand) {
|
|
226
|
+
yajl_free(hand);
|
|
227
|
+
}
|
|
228
|
+
rb_raise(cParseError, "%s", err);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void Init_parser() {
|
|
232
|
+
mFFI_Yajl = rb_define_module("FFI_Yajl");
|
|
233
|
+
cParseError = rb_define_class_under(mFFI_Yajl, "ParseError", rb_eStandardError);
|
|
234
|
+
mExt = rb_define_module_under(mFFI_Yajl, "Ext");
|
|
235
|
+
mParser = rb_define_module_under(mExt, "Parser");
|
|
236
|
+
rb_define_method(mParser, "do_yajl_parse", mParser_do_yajl_parse, 2);
|
|
237
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
238
|
+
utf8Encoding = rb_utf8_encoding();
|
|
239
|
+
#endif
|
|
240
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2008-2011 Brian Lopez - http://github.com/brianmario
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Portions Originally Copyright (c) 2008-2011 Brian Lopez - http://github.com/brianmario
|
|
2
|
+
# See MIT-LICENSE
|
|
3
|
+
|
|
4
|
+
require "rubygems" unless defined?(Gem)
|
|
5
|
+
require "benchmark" unless defined?(Benchmark)
|
|
6
|
+
require "stringio" unless defined?(StringIO)
|
|
7
|
+
if !defined?(RUBY_ENGINE) || RUBY_ENGINE !~ /jruby/
|
|
8
|
+
begin
|
|
9
|
+
require "yajl"
|
|
10
|
+
rescue LoadError
|
|
11
|
+
puts "INFO: yajl-ruby not installed"
|
|
12
|
+
end
|
|
13
|
+
else
|
|
14
|
+
puts "INFO: skipping yajl-ruby on jruby"
|
|
15
|
+
end
|
|
16
|
+
require_relative "../../ffi_yajl"
|
|
17
|
+
begin
|
|
18
|
+
require "json" unless defined?(JSON)
|
|
19
|
+
rescue LoadError
|
|
20
|
+
puts "INFO: json gem not installed"
|
|
21
|
+
end
|
|
22
|
+
begin
|
|
23
|
+
require "oj"
|
|
24
|
+
rescue LoadError
|
|
25
|
+
puts "INFO: oj gem not installed"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module FFI_Yajl
|
|
29
|
+
class Benchmark
|
|
30
|
+
class Encode
|
|
31
|
+
def run
|
|
32
|
+
# filename = ARGV[0] || 'benchmark/subjects/ohai.json'
|
|
33
|
+
filename = File.expand_path(File.join(File.dirname(__FILE__), "subjects", "ohai.json"))
|
|
34
|
+
hash = File.open(filename, "rb") { |f| FFI_Yajl::Parser.parse(f.read) }
|
|
35
|
+
|
|
36
|
+
times = ARGV[1] ? ARGV[1].to_i : 1000
|
|
37
|
+
puts "Starting benchmark encoding #{filename} #{times} times\n\n"
|
|
38
|
+
::Benchmark.bmbm do |x|
|
|
39
|
+
x.report("FFI_Yajl::Encoder.encode (to a String)") do
|
|
40
|
+
times.times { FFI_Yajl::Encoder.encode(hash) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
ffi_string_encoder = FFI_Yajl::Encoder.new
|
|
44
|
+
x.report("FFI_Yajl::Encoder#encode (to a String)") do
|
|
45
|
+
times.times { ffi_string_encoder.encode(hash) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if defined?(Oj)
|
|
49
|
+
x.report("Oj.dump (to a String)") do
|
|
50
|
+
times.times { Oj.dump(hash) }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if defined?(Yajl::Encoder)
|
|
55
|
+
x.report("Yajl::Encoder.encode (to a String)") do
|
|
56
|
+
times.times { Yajl::Encoder.encode(hash) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
io_encoder = Yajl::Encoder.new
|
|
60
|
+
x.report("Yajl::Encoder#encode (to an IO)") do
|
|
61
|
+
times.times { io_encoder.encode(hash, StringIO.new) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
string_encoder = Yajl::Encoder.new
|
|
65
|
+
x.report("Yajl::Encoder#encode (to a String)") do
|
|
66
|
+
times.times { string_encoder.encode(hash) }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if defined?(JSON)
|
|
71
|
+
x.report("JSON.generate") do
|
|
72
|
+
times.times { JSON.generate(hash) }
|
|
73
|
+
end
|
|
74
|
+
x.report("JSON.fast_generate") do
|
|
75
|
+
times.times { JSON.fast_generate(hash) }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/..")
|
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
|
3
|
+
|
|
4
|
+
require "rubygems" unless defined?(Gem)
|
|
5
|
+
require "benchmark" unless defined?(Benchmark)
|
|
6
|
+
require "yajl"
|
|
7
|
+
require "stringio" unless defined?(StringIO)
|
|
8
|
+
begin
|
|
9
|
+
require "json" unless defined?(JSON)
|
|
10
|
+
rescue LoadError
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
times = ARGV[0] ? ARGV[0].to_i : 1000
|
|
14
|
+
filename = "benchmark/subjects/ohai.json"
|
|
15
|
+
json = File.new(filename, "r")
|
|
16
|
+
hash = Yajl::Parser.new.parse(json)
|
|
17
|
+
json.close
|
|
18
|
+
|
|
19
|
+
puts "Starting benchmark encoding #{filename} #{times} times\n\n"
|
|
20
|
+
Benchmark.bmbm do |x|
|
|
21
|
+
encoder = Yajl::Encoder.new
|
|
22
|
+
x.report do
|
|
23
|
+
puts "Yajl::Encoder#encode"
|
|
24
|
+
times.times do
|
|
25
|
+
encoder.encode(hash, StringIO.new)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
if defined?(JSON)
|
|
29
|
+
x.report do
|
|
30
|
+
puts "JSON's #to_json"
|
|
31
|
+
times.times do
|
|
32
|
+
JSON.generate(hash)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
x.report do
|
|
37
|
+
puts "Marshal.dump"
|
|
38
|
+
times.times do
|
|
39
|
+
Marshal.dump(hash)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/..")
|
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
|
3
|
+
|
|
4
|
+
require "rubygems" unless defined?(Gem)
|
|
5
|
+
require "benchmark" unless defined?(Benchmark)
|
|
6
|
+
require "yajl"
|
|
7
|
+
begin
|
|
8
|
+
require "json" unless defined?(JSON)
|
|
9
|
+
rescue LoadError
|
|
10
|
+
end
|
|
11
|
+
require "yaml" unless defined?(YAML)
|
|
12
|
+
|
|
13
|
+
# JSON Section
|
|
14
|
+
filename = "benchmark/subjects/ohai.json"
|
|
15
|
+
json = File.new(filename, "r")
|
|
16
|
+
hash = Yajl::Parser.new.parse(json)
|
|
17
|
+
json.close
|
|
18
|
+
|
|
19
|
+
times = ARGV[0] ? ARGV[0].to_i : 1000
|
|
20
|
+
puts "Starting benchmark encoding #{filename} into JSON #{times} times\n\n"
|
|
21
|
+
Benchmark.bmbm do |x|
|
|
22
|
+
encoder = Yajl::Encoder.new
|
|
23
|
+
x.report do
|
|
24
|
+
puts "Yajl::Encoder#encode"
|
|
25
|
+
times.times { encoder.encode(hash, StringIO.new) }
|
|
26
|
+
end
|
|
27
|
+
if defined?(JSON)
|
|
28
|
+
x.report do
|
|
29
|
+
puts "JSON's #to_json"
|
|
30
|
+
times.times { JSON.generate(hash) }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# YAML Section
|
|
36
|
+
filename = "benchmark/subjects/ohai.yml"
|
|
37
|
+
yml = File.new(filename, "r")
|
|
38
|
+
data = YAML.load_stream(yml)
|
|
39
|
+
yml.close
|
|
40
|
+
|
|
41
|
+
puts "Starting benchmark encoding #{filename} into YAML #{times} times\n\n"
|
|
42
|
+
Benchmark.bmbm do |x|
|
|
43
|
+
x.report do
|
|
44
|
+
puts "YAML.dump"
|
|
45
|
+
times.times { YAML.dump(data, StringIO.new) }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Portions Originally Copyright (c) 2008-2011 Brian Lopez - http://github.com/brianmario
|
|
2
|
+
# See MIT-LICENSE
|
|
3
|
+
|
|
4
|
+
require "rubygems" unless defined?(Gem)
|
|
5
|
+
require_relative "../../ffi_yajl"
|
|
6
|
+
begin
|
|
7
|
+
require "perftools"
|
|
8
|
+
rescue LoadError
|
|
9
|
+
puts "INFO: perftools.rb gem not installed"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
ENV["CPUPROFILE_FREQUENCY"] = "4000"
|
|
13
|
+
|
|
14
|
+
module FFI_Yajl
|
|
15
|
+
class Benchmark
|
|
16
|
+
class EncodeProfile
|
|
17
|
+
def run
|
|
18
|
+
return unless defined?(PerfTools)
|
|
19
|
+
|
|
20
|
+
filename = File.expand_path(File.join(File.dirname(__FILE__), "subjects", "ohai.json"))
|
|
21
|
+
hash = File.open(filename, "rb") { |f| FFI_Yajl::Parser.parse(f.read) }
|
|
22
|
+
|
|
23
|
+
times = 1000
|
|
24
|
+
puts "Starting profiling encoding #{filename} #{times} times\n\n"
|
|
25
|
+
|
|
26
|
+
ffi_string_encoder = FFI_Yajl::Encoder.new
|
|
27
|
+
PerfTools::CpuProfiler.start("/tmp/ffi_yajl_encode_profile.out") do
|
|
28
|
+
times.times { ffi_string_encoder.encode(hash) }
|
|
29
|
+
end
|
|
30
|
+
system("pprof.rb --text /tmp/ffi_yajl_encode_profile.out")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/..")
|
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
|
3
|
+
|
|
4
|
+
require "rubygems" unless defined?(Gem)
|
|
5
|
+
require "benchmark" unless defined?(Benchmark)
|
|
6
|
+
require "yajl/http_stream"
|
|
7
|
+
require "yajl/gzip"
|
|
8
|
+
require "yajl/deflate"
|
|
9
|
+
require "yajl/bzip2" unless defined?(Bzip2)
|
|
10
|
+
require "json" unless defined?(JSON)
|
|
11
|
+
require "uri" unless defined?(URI)
|
|
12
|
+
require "net/http" unless defined?(Net::HTTP)
|
|
13
|
+
|
|
14
|
+
uri = URI.parse("http://search.twitter.com/search.json?q=github")
|
|
15
|
+
# uri = URI.parse('http://localhost/yajl-ruby.git/benchmark/subjects/contacts.json')
|
|
16
|
+
|
|
17
|
+
times = ARGV[0] ? ARGV[0].to_i : 1
|
|
18
|
+
puts "Starting benchmark parsing #{uri} #{times} times\n\n"
|
|
19
|
+
Benchmark.bmbm do |x|
|
|
20
|
+
x.report do
|
|
21
|
+
puts "Yajl::HttpStream.get"
|
|
22
|
+
times.times { Yajl::HttpStream.get(uri) }
|
|
23
|
+
end
|
|
24
|
+
x.report do
|
|
25
|
+
puts "JSON.parser"
|
|
26
|
+
times.times { JSON.parse(Net::HTTP.get_response(uri).body, max_nesting: false) }
|
|
27
|
+
end
|
|
28
|
+
end
|