From f13c0269f45a6822fd64fe90042677eaf0dd1cb3 Mon Sep 17 00:00:00 2001 From: Chris Griego Date: Mon, 21 Jan 2013 17:46:33 -0600 Subject: [PATCH] Optimize BSON::ObjectId.from_string and BSON::ObjectID.legal? via C extensions. --- ext/cbson/cbson.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/ext/cbson/cbson.c b/ext/cbson/cbson.c index a4665ba1b1..aa383d14cd 100644 --- a/ext/cbson/cbson.c +++ b/ext/cbson/cbson.c @@ -93,6 +93,7 @@ static VALUE OrderedHash; static VALUE InvalidKeyName; static VALUE InvalidStringEncoding; static VALUE InvalidDocument; +static VALUE InvalidObjectId; static VALUE DigestMD5; static VALUE RB_HASH; @@ -924,6 +925,64 @@ static VALUE method_deserialize(VALUE self, VALUE bson) { return elements_to_hash(buffer, remaining); } +static int legal_objectid_str(VALUE str) { + int i; + + if (TYPE(str) != T_STRING) { + return 0; + } + + if (RSTRING_LEN(str) != 24) { + return 0; + } + + for(i = 0; i < 24; i++) { + char c = RSTRING_PTR(str)[i]; + + if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) { + return 0; + } + } + + return 1; +} + +static VALUE objectid_legal(VALUE self, VALUE str) +{ + if (legal_objectid_str(str)) + return Qtrue; + return Qfalse; +} + +static char hexbyte( char hex ) { + if (hex >= '0' && hex <= '9') + return (hex - '0'); + else if (hex >= 'A' && hex <= 'F') + return (hex - 'A' + 10); + else if (hex >= 'a' && hex <= 'f') + return (hex - 'a' + 10); + else + return 0x0; +} + +static VALUE objectid_from_string(VALUE self, VALUE str) +{ + VALUE oid; + int i; + + if (!legal_objectid_str(str)) { + rb_raise(InvalidObjectId, "illegal ObjectId format: %s", RSTRING_PTR(str)); + } + + oid = rb_ary_new2(12); + + for(i = 0; i < 12; i++) { + rb_ary_store(oid, i, INT2FIX( (unsigned)(hexbyte( RSTRING_PTR(str)[2*i] ) << 4 ) | hexbyte( RSTRING_PTR(str)[2*i + 1] ))); + } + + return rb_class_new_instance(1, &oid, ObjectId); +} + static VALUE objectid_generate(int argc, VALUE* args, VALUE self) { VALUE oid; @@ -1002,6 +1061,7 @@ void Init_cbson() { InvalidKeyName = rb_const_get(bson, rb_intern("InvalidKeyName")); InvalidStringEncoding = rb_const_get(bson, rb_intern("InvalidStringEncoding")); InvalidDocument = rb_const_get(bson, rb_intern("InvalidDocument")); + InvalidObjectId = rb_const_get(bson, rb_intern("InvalidObjectId")); rb_require("bson/ordered_hash"); OrderedHash = rb_const_get(bson, rb_intern("OrderedHash")); RB_HASH = rb_const_get(bson, rb_intern("Hash")); @@ -1018,6 +1078,8 @@ void Init_cbson() { Digest = rb_const_get(rb_cObject, rb_intern("Digest")); DigestMD5 = rb_const_get(Digest, rb_intern("MD5")); + rb_define_singleton_method(ObjectId, "legal?", objectid_legal, 1); + rb_define_singleton_method(ObjectId, "from_string", objectid_from_string, 1); rb_define_method(ObjectId, "generate", objectid_generate, -1); if (gethostname(hostname, MAX_HOSTNAME_LENGTH) != 0) {