animehunter-mongo_ext 0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'rubygems/specification'
3
+ require 'fileutils'
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+ require 'rake/gempackagetask'
7
+ begin
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ rescue LoadError
10
+ end
11
+ require 'rbconfig'
12
+ include Config
13
+
14
+ gem_command = "gem"
15
+ gem_command = "gem1.9" if CONFIG["MAJOR"] == "1" && CONFIG["MINOR"] == "9"
16
+
17
+ # NOTE: some of the tests assume Mongo is running
18
+ Rake::TestTask.new do |t|
19
+ t.test_files = FileList['tests/test*.rb']
20
+ end
21
+
22
+ desc "Generate documentation"
23
+ task :rdoc do
24
+ version = eval(File.read("mongo-ruby-driver.gemspec")).version
25
+ out = File.join('html', version.to_s)
26
+ FileUtils.rm_rf('html')
27
+ system "rdoc --main README.rdoc --op #{out} --inline-source --quiet README.rdoc `find lib -name '*.rb'`"
28
+ end
29
+
30
+ desc "Publish documentation to mongo.rubyforge.org"
31
+ task :publish => [:rdoc] do
32
+ # Assumes docs are in ./html
33
+ Rake::RubyForgePublisher.new(GEM, RUBYFORGE_USER).upload
34
+ end
35
+
36
+ namespace :gem do
37
+
38
+ desc "Install the gem locally"
39
+ task :install do
40
+ sh <<EOS
41
+ #{gem_command} build mongo-ruby-driver.gemspec &&
42
+ sudo #{gem_command} install mongo-*.gem &&
43
+ rm mongo-*.gem
44
+ EOS
45
+ end
46
+
47
+ desc "Install the optional c extensions"
48
+ task :install_extensions do
49
+ sh <<EOS
50
+ #{gem_command} build mongo-extensions.gemspec &&
51
+ sudo #{gem_command} install mongo_ext-*.gem &&
52
+ rm mongo_ext-*.gem
53
+ EOS
54
+ end
55
+
56
+ end
57
+
58
+ task :default => :list
59
+
60
+ task :list do
61
+ system 'rake -T'
62
+ end
data/ext/cbson/cbson.c ADDED
@@ -0,0 +1,347 @@
1
+ /*
2
+ * Copyright 2009 10gen, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ /*
18
+ * This file contains C implementations of some of the functions needed by the
19
+ * bson module. If possible, these implementations should be used to speed up
20
+ * BSON encoding and decoding.
21
+ */
22
+
23
+ #include "ruby.h"
24
+
25
+
26
+ #if HAVE_RUBY_ST_H
27
+ #include "ruby/st.h"
28
+ #endif
29
+ #if HAVE_ST_H
30
+ #include "st.h"
31
+ #endif
32
+
33
+ #if HAVE_RUBY_REGEX_H
34
+ #include "ruby/regex.h"
35
+ #endif
36
+ #if HAVE_REGEX_H
37
+ #include "regex.h"
38
+ #endif
39
+
40
+ #include <assert.h>
41
+ #include <math.h>
42
+
43
+
44
+ #define INITIAL_BUFFER_SIZE 256
45
+
46
+ static VALUE Binary;
47
+ static VALUE Undefined;
48
+ static VALUE Time;
49
+ static VALUE ObjectID;
50
+ static VALUE DBRef;
51
+ static VALUE Code;
52
+ static VALUE RegexpOfHolding;
53
+ static VALUE OrderedHash;
54
+
55
+ // this sucks. but for some reason these moved around between 1.8 and 1.9
56
+ #ifdef ONIGURUMA_H
57
+ #define IGNORECASE ONIG_OPTION_IGNORECASE
58
+ #define MULTILINE ONIG_OPTION_MULTILINE
59
+ #define EXTENDED ONIG_OPTION_EXTEND
60
+ #else
61
+ #define IGNORECASE RE_OPTION_IGNORECASE
62
+ #define MULTILINE RE_OPTION_MULTILINE
63
+ #define EXTENDED RE_OPTION_EXTENDED
64
+ #endif
65
+
66
+ /* TODO we ought to check that the malloc or asprintf was successful
67
+ * and raise an exception if not. */
68
+ #ifdef _MSC_VER
69
+ #define INT2STRING(buffer, i) \
70
+ { \
71
+ int vslength = _scprintf("%d", i) + 1; \
72
+ *buffer = malloc(vslength); \
73
+ _snprintf(*buffer, vslength, "%d", i); \
74
+ }
75
+ #elif defined(__MINGW32__)
76
+ #define INT2STRING(buffer, i) \
77
+ { \
78
+ int vslength = log10(i) + 2; \
79
+ *buffer = malloc(vslength); \
80
+ _snprintf(*buffer, vslength, "%d", i); \
81
+ }
82
+ #else
83
+ #define INT2STRING(buffer, i) asprintf(buffer, "%d", i);
84
+ #endif
85
+
86
+ // this sucks too.
87
+ #ifndef RREGEXP_SRC_PTR
88
+ #define RREGEXP_SRC_PTR(r) RREGEXP(r)->str
89
+ #define RREGEXP_SRC_LEN(r) RREGEXP(r)->len
90
+ #endif
91
+
92
+ typedef struct {
93
+ char* buffer;
94
+ int size;
95
+ int position;
96
+ } bson_buffer;
97
+
98
+ static char zero = 0;
99
+ static char one = 1;
100
+
101
+ static int cmp_char(const void* a, const void* b) {
102
+ return *(char*)a - *(char*)b;
103
+ }
104
+
105
+ static void write_doc(bson_buffer* buffer, VALUE hash, VALUE check_keys);
106
+ static int write_element(VALUE key, VALUE value, VALUE extra);
107
+ static VALUE elements_to_hash(const char* buffer, int max);
108
+
109
+ static bson_buffer* buffer_new(void) {
110
+ bson_buffer* buffer;
111
+ buffer = ALLOC(bson_buffer);
112
+ assert(buffer);
113
+
114
+ buffer->size = INITIAL_BUFFER_SIZE;
115
+ buffer->position = 0;
116
+ buffer->buffer = ALLOC_N(char, INITIAL_BUFFER_SIZE);
117
+ assert(buffer->buffer);
118
+
119
+ return buffer;
120
+ }
121
+
122
+ static void buffer_free(bson_buffer* buffer) {
123
+ assert(buffer);
124
+ assert(buffer->buffer);
125
+
126
+ free(buffer->buffer);
127
+ free(buffer);
128
+ }
129
+
130
+ static void buffer_resize(bson_buffer* buffer, int min_length) {
131
+ int size = buffer->size;
132
+ if (size >= min_length) {
133
+ return;
134
+ }
135
+ while (size < min_length) {
136
+ size *= 2;
137
+ }
138
+ buffer->buffer = REALLOC_N(buffer->buffer, char, size);
139
+ assert(buffer->buffer);
140
+ buffer->size = size;
141
+ }
142
+
143
+ static void buffer_assure_space(bson_buffer* buffer, int size) {
144
+ if (buffer->position + size <= buffer->size) {
145
+ return;
146
+ }
147
+ buffer_resize(buffer, buffer->position + size);
148
+ }
149
+
150
+ /* returns offset for writing */
151
+ static int buffer_save_bytes(bson_buffer* buffer, int size) {
152
+ int position = buffer->position;
153
+ buffer_assure_space(buffer, size);
154
+ buffer->position += size;
155
+ return position;
156
+ }
157
+
158
+ static void buffer_write_bytes(bson_buffer* buffer, const char* bytes, int size) {
159
+ buffer_assure_space(buffer, size);
160
+
161
+ memcpy(buffer->buffer + buffer->position, bytes, size);
162
+ buffer->position += size;
163
+ }
164
+
165
+ static VALUE pack_extra(bson_buffer* buffer, VALUE check_keys) {
166
+ return rb_ary_new3(2, INT2NUM((int)buffer), check_keys);
167
+ }
168
+
169
+ static void write_name_and_type(bson_buffer* buffer, VALUE name, char type) {
170
+ buffer_write_bytes(buffer, &type, 1);
171
+ buffer_write_bytes(buffer, RSTRING_PTR(name), RSTRING_LEN(name));
172
+ buffer_write_bytes(buffer, &zero, 1);
173
+ }
174
+
175
+ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow_id) {
176
+ bson_buffer* buffer = (bson_buffer*)NUM2INT(rb_ary_entry(extra, 0));
177
+ VALUE check_keys = rb_ary_entry(extra, 1);
178
+
179
+ if (TYPE(key) == T_SYMBOL) {
180
+ // TODO better way to do this... ?
181
+ key = rb_str_new2(rb_id2name(SYM2ID(key)));
182
+ }
183
+
184
+ if (TYPE(key) != T_STRING) {
185
+ rb_raise(rb_eTypeError, "keys must be strings or symbols");
186
+ }
187
+
188
+ if (!allow_id && strcmp("_id", RSTRING_PTR(key)) == 0) {
189
+ return ST_CONTINUE;
190
+ }
191
+
192
+ if (check_keys == Qtrue) {
193
+ int i;
194
+ if (RSTRING_LEN(key) > 0 && RSTRING_PTR(key)[0] == '$') {
195
+ rb_raise(rb_eRuntimeError, "key must not start with '$'");
196
+ }
197
+ for (i = 0; i < RSTRING_LEN(key); i++) {
198
+ if (RSTRING_PTR(key)[i] == '.') {
199
+ rb_raise(rb_eRuntimeError, "key must not contain '.'");
200
+ }
201
+ }
202
+ }
203
+
204
+ switch(TYPE(value)) {
205
+ case T_BIGNUM:
206
+ {
207
+ VALUE as_f;
208
+ int int_value;
209
+ if (rb_funcall(value, rb_intern(">"), 1, INT2NUM(2147483647)) == Qtrue ||
210
+ rb_funcall(value, rb_intern("<"), 1, INT2NUM(-2147483648)) == Qtrue) {
211
+ rb_raise(rb_eRangeError, "MongoDB can only handle 4-byte ints"
212
+ " - try converting to a double before saving");
213
+ }
214
+ write_name_and_type(buffer, key, 0x10);
215
+ as_f = rb_funcall(value, rb_intern("to_f"), 0);
216
+ int_value = NUM2LL(as_f);
217
+ buffer_write_bytes(buffer, (char*)&int_value, 4);
218
+ break;
219
+ }
220
+ case T_FIXNUM:
221
+ {
222
+ int int_value = FIX2INT(value);
223
+ write_name_and_type(buffer, key, 0x10);
224
+ buffer_write_bytes(buffer, (char*)&int_value, 4);
225
+ break;
226
+ }
227
+ case T_TRUE:
228
+ {
229
+ write_name_and_type(buffer, key, 0x08);
230
+ buffer_write_bytes(buffer, &one, 1);
231
+ break;
232
+ }
233
+ case T_FALSE:
234
+ {
235
+ write_name_and_type(buffer, key, 0x08);
236
+ buffer_write_bytes(buffer, &zero, 1);
237
+ break;
238
+ }
239
+ case T_FLOAT:
240
+ {
241
+ double d = NUM2DBL(value);
242
+ write_name_and_type(buffer, key, 0x01);
243
+ buffer_write_bytes(buffer, (char*)&d, 8);
244
+ break;
245
+ }
246
+ case T_NIL:
247
+ {
248
+ write_name_and_type(buffer, key, 0x0A);
249
+ break;
250
+ }
251
+ case T_HASH:
252
+ {
253
+ write_name_and_type(buffer, key, 0x03);
254
+ write_doc(buffer, value, check_keys);
255
+ break;
256
+ }
257
+ case T_ARRAY:
258
+ {
259
+ int start_position, length_location, items, i, obj_length;
260
+ VALUE* values;
261
+
262
+ write_name_and_type(buffer, key, 0x04);
263
+ start_position = buffer->position;
264
+
265
+ // save space for length
266
+ length_location = buffer_save_bytes(buffer, 4);
267
+
268
+ items = RARRAY_LEN(value);
269
+ values = RARRAY_PTR(value);
270
+ for(i = 0; i < items; i++) {
271
+ char* name;
272
+ VALUE key;
273
+ INT2STRING(&name, i);
274
+ key = rb_str_new2(name);
275
+ write_element(key, values[i], pack_extra(buffer, check_keys));
276
+ free(name);
277
+ }
278
+
279
+ // write null byte and fill in length
280
+ buffer_write_bytes(buffer, &zero, 1);
281
+ obj_length = buffer->position - start_position;
282
+ memcpy(buffer->buffer + length_location, &obj_length, 4);
283
+ break;
284
+ }
285
+ case T_STRING:
286
+ {
287
+ if (strcmp(rb_class2name(RBASIC(value)->klass),
288
+ "XGen::Mongo::Driver::Code") == 0) {
289
+ int start_position, length_location, length, total_length;
290
+ write_name_and_type(buffer, key, 0x0F);
291
+
292
+ start_position = buffer->position;
293
+ length_location = buffer_save_bytes(buffer, 4);
294
+
295
+ length = RSTRING_LEN(value) + 1;
296
+ buffer_write_bytes(buffer, (char*)&length, 4);
297
+ buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1);
298
+ buffer_write_bytes(buffer, &zero, 1);
299
+ write_doc(buffer, rb_funcall(value, rb_intern("scope"), 0), Qfalse);
300
+
301
+ total_length = buffer->position - start_position;
302
+ memcpy(buffer->buffer + length_location, &total_length, 4);
303
+
304
+ break;
305
+ } else {
306
+ int length = RSTRING_LEN(value) + 1;
307
+ write_name_and_type(buffer, key, 0x02);
308
+ buffer_write_bytes(buffer, (char*)&length, 4);
309
+ buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1);
310
+ buffer_write_bytes(buffer, &zero, 1);
311
+ break;
312
+ }
313
+ }
314
+ case T_SYMBOL:
315
+ {
316
+ const char* str_value = rb_id2name(SYM2ID(value));
317
+ int length = strlen(str_value) + 1;
318
+ write_name_and_type(buffer, key, 0x0E);
319
+ buffer_write_bytes(buffer, (char*)&length, 4);
320
+ buffer_write_bytes(buffer, str_value, length);
321
+ break;
322
+ }
323
+ case T_OBJECT:
324
+ {
325
+ // TODO there has to be a better way to do these checks...
326
+ const char* cls = rb_class2name(RBASIC(value)->klass);
327
+ if (strcmp(cls, "XGen::Mongo::Driver::Binary") == 0 ||
328
+ strcmp(cls, "ByteBuffer") == 0) {
329
+ const char subtype = strcmp(cls, "ByteBuffer") ?
330
+ (const char)FIX2INT(rb_funcall(value, rb_intern("subtype"), 0)) : 2;
331
+ VALUE string_data = rb_funcall(value, rb_intern("to_s"), 0);
332
+ int length = RSTRING_LEN(string_data);
333
+ write_name_and_type(buffer, key, 0x05);
334
+ if (subtype == 2) {
335
+ const int other_length = length + 4;
336
+ buffer_write_bytes(buffer, (const char*)&other_length, 4);
337
+ buffer_write_bytes(buffer, &subtype, 1);
338
+ }
339
+ buffer_write_bytes(buffer, (const char*)&length, 4);
340
+ if (subtype != 2) {
341
+ buffer_write_bytes(buffer, &subtype, 1);
342
+ }
343
+ buffer_write_bytes(buffer, RSTRING_PTR(string_data), length);
344
+ break;
345
+ }
346
+ if (strcmp(cls, "XGen::Mongo::Driver::ObjectID") == 0) {
347
+ VALUE as_array = rb_funcall(value, rb_intern("to_a%
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ find_header("st.h")
4
+ find_header("regex.h")
5
+ dir_config('cbson')
6
+ create_makefile('mongo_ext/cbson')
@@ -0,0 +1,26 @@
1
+ # We need to list all of the included files because we aren't allowed to use
2
+ # Dir[...] in the github sandbox.
3
+ PACKAGE_FILES = ['Rakefile', 'mongo-extensions.gemspec',
4
+ 'ext/cbson/cbson.c',
5
+ 'ext/cbson/extconf.rb']
6
+ TEST_FILES = []
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = 'mongo_ext'
10
+ s.version = '0.3'
11
+ s.platform = Gem::Platform::RUBY
12
+ s.summary = 'C extensions for the MongoDB Ruby driver'
13
+ s.description = 'C extensions to accelerate the MondoDB Ruby driver. For more information about Mongo, see http://www.mongodb.org.'
14
+
15
+ s.require_paths = ['ext']
16
+
17
+ s.files = PACKAGE_FILES
18
+ s.test_files = TEST_FILES
19
+
20
+ s.has_rdoc = false
21
+ s.extensions << 'ext/cbson/extconf.rb'
22
+
23
+ s.author = 'Mike Dirolf'
24
+ s.email = 'mongodb-dev@googlegroups.com'
25
+ s.homepage = 'http://www.mongodb.org'
26
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: animehunter-mongo_ext
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.3"
5
+ platform: ruby
6
+ authors:
7
+ - Mike Dirolf
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: C extensions to accelerate the MondoDB Ruby driver. For more information about Mongo, see http://www.mongodb.org.
17
+ email: mongodb-dev@googlegroups.com
18
+ executables: []
19
+
20
+ extensions:
21
+ - ext/cbson/extconf.rb
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - Rakefile
26
+ - mongo-extensions.gemspec
27
+ - ext/cbson/cbson.c
28
+ - ext/cbson/extconf.rb
29
+ has_rdoc: false
30
+ homepage: http://www.mongodb.org
31
+ licenses:
32
+ post_install_message:
33
+ rdoc_options: []
34
+
35
+ require_paths:
36
+ - ext
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: "0"
42
+ version:
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.3.5
53
+ signing_key:
54
+ specification_version: 2
55
+ summary: C extensions for the MongoDB Ruby driver
56
+ test_files: []
57
+