Skip to content

Commit

Permalink
Added MinKey and MaxKey support to C++ parser
Browse files Browse the repository at this point in the history
  • Loading branch information
christkv committed Oct 4, 2011
1 parent e1c472d commit ce6419e
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 44 deletions.
86 changes: 83 additions & 3 deletions external-libs/bson/bson.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "code.h"
#include "dbref.h"
#include "symbol.h"
#include "minkey.h"
#include "maxkey.h"

using namespace v8;
using namespace node;
Expand All @@ -40,7 +42,8 @@ const uint32_t BSON_DATA_CODE_W_SCOPE = 15;
const uint32_t BSON_DATA_INT = 16;
const uint32_t BSON_DATA_TIMESTAMP = 17;
const uint32_t BSON_DATA_LONG = 18;

const uint32_t BSON_DATA_MIN_KEY = 0xff;
const uint32_t BSON_DATA_MAX_KEY = 0x7f;

const int32_t BSON_INT32_MAX = (int32_t)2147483647L;
const int32_t BSON_INT32_MIN = (int32_t)(-1) * 2147483648L;
Expand Down Expand Up @@ -559,7 +562,31 @@ uint32_t BSON::serialize(char *serialized_object, uint32_t index, Handle<Value>
*(serialized_object + index + str->Length()) = '\0';
// Adjust the index
index = index + str->Length() + 1;
}
}
} else if(MinKey::HasInstance(value)) {
// Save the string at the offset provided
*(serialized_object + index) = BSON_DATA_MIN_KEY;
// Adjust writing position for the first byte
index = index + 1;
// Convert name to char*
ssize_t len = DecodeBytes(name, UTF8);
ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
// Add null termiation for the string
*(serialized_object + index + len) = '\0';
// Adjust the index
index = index + len + 1;
} else if(MaxKey::HasInstance(value)) {
// Save the string at the offset provided
*(serialized_object + index) = BSON_DATA_MAX_KEY;
// Adjust writing position for the first byte
index = index + 1;
// Convert name to char*
ssize_t len = DecodeBytes(name, UTF8);
ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
// Add null termiation for the string
*(serialized_object + index + len) = '\0';
// Adjust the index
index = index + len + 1;
} else if(value->IsNull() || value->IsUndefined()) {
// Save the string at the offset provided
*(serialized_object + index) = BSON_DATA_NULL;
Expand Down Expand Up @@ -787,6 +814,9 @@ uint32_t BSON::serialize(char *serialized_object, uint32_t index, Handle<Value>
|| constructorString->Equals(String::New("Binary"))
|| constructorString->Equals(String::New("exports.DBRef"))
|| constructorString->Equals(String::New("exports.Code"))
|| constructorString->Equals(String::New("exports.Double"))
|| constructorString->Equals(String::New("exports.MinKey"))
|| constructorString->Equals(String::New("exports.MaxKey"))
|| constructorString->Equals(String::New("exports.Symbol")))) {

// Throw an error due to wrong class
Expand Down Expand Up @@ -906,6 +936,7 @@ uint32_t BSON::calculate_object_size(Handle<Value> value) {
if(db_ref_obj->db != NULL) obj->Set(String::New("$db"), dbref->Get(String::New("db")));
// Calculate size
object_size += BSON::calculate_object_size(obj);
} else if(MinKey::HasInstance(value) || MaxKey::HasInstance(value)) {
} else if(Symbol::HasInstance(value)) {
// Unpack the dbref
Local<Object> dbref = value->ToObject();
Expand Down Expand Up @@ -998,6 +1029,9 @@ uint32_t BSON::calculate_object_size(Handle<Value> value) {
|| constructorString->Equals(String::New("Binary"))
|| constructorString->Equals(String::New("exports.DBRef"))
|| constructorString->Equals(String::New("exports.Code"))
|| constructorString->Equals(String::New("exports.Double"))
|| constructorString->Equals(String::New("exports.MinKey"))
|| constructorString->Equals(String::New("exports.MaxKey"))
|| constructorString->Equals(String::New("exports.Symbol")))) {

// Throw an error due to wrong class
Expand Down Expand Up @@ -1104,7 +1138,7 @@ Handle<Value> BSON::deserialize(char *data, bool is_array_item) {
// While we have data left let's decode
while(index < size) {
// Read the first to bytes to indicate the type of object we are decoding
uint16_t type = BSON::deserialize_int8(data, index);
uint8_t type = BSON::deserialize_int8(data, index);
// Handles the internal size of the object
uint32_t insert_index = 0;
// Adjust index to skip type byte
Expand Down Expand Up @@ -1246,6 +1280,50 @@ Handle<Value> BSON::deserialize(char *data, bool is_array_item) {
}
// Free up the memory
free(string_name);
} else if(type == BSON_DATA_MIN_KEY) {
// Read the null terminated index String
char *string_name = BSON::extract_string(data, index);
if(string_name == NULL) return VException("Invalid C String found.");
// Let's create a new string
index = index + strlen(string_name) + 1;
// Handle array value if applicable
uint32_t insert_index = 0;
if(is_array_item) {
insert_index = atoi(string_name);
}

// Create new MinKey
MinKey *minKey = MinKey::New();
// Add the element to the object
if(is_array_item) {
return_array->Set(Number::New(insert_index), minKey->handle_);
} else {
return_data->Set(String::New(string_name), minKey->handle_);
}
// Free up the memory
free(string_name);
} else if(type == BSON_DATA_MAX_KEY) {
// Read the null terminated index String
char *string_name = BSON::extract_string(data, index);
if(string_name == NULL) return VException("Invalid C String found.");
// Let's create a new string
index = index + strlen(string_name) + 1;
// Handle array value if applicable
uint32_t insert_index = 0;
if(is_array_item) {
insert_index = atoi(string_name);
}

// Create new MinKey
MaxKey *maxKey = MaxKey::New();
// Add the element to the object
if(is_array_item) {
return_array->Set(Number::New(insert_index), maxKey->handle_);
} else {
return_data->Set(String::New(string_name), maxKey->handle_);
}
// Free up the memory
free(string_name);
} else if(type == BSON_DATA_NULL) {
// Read the null terminated index String
char *string_name = BSON::extract_string(data, index);
Expand Down Expand Up @@ -1870,6 +1948,8 @@ extern "C" void init(Handle<Object> target) {
DBRef::Initialize(target);
Timestamp::Initialize(target);
Symbol::Initialize(target);
MinKey::Initialize(target);
MaxKey::Initialize(target);
}

// NODE_MODULE(bson, BSON::Initialize);
Expand Down
2 changes: 1 addition & 1 deletion external-libs/bson/wscript
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def configure(conf):
def build(bld):
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
obj.target = "bson"
obj.source = ["bson.cc", "long.cc", "objectid.cc", "binary.cc", "code.cc", "dbref.cc", "timestamp.cc", "local.cc", "symbol.cc"]
obj.source = ["bson.cc", "long.cc", "objectid.cc", "binary.cc", "code.cc", "dbref.cc", "timestamp.cc", "local.cc", "symbol.cc", "minkey.cc", "maxkey.cc"]
# obj.uselib = "NODE"

def shutdown():
Expand Down
101 changes: 61 additions & 40 deletions lib/mongodb/bson/bson.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ BSON.BSON_DATA_CODE_W_SCOPE = 15;
BSON.BSON_DATA_INT = 16;
BSON.BSON_DATA_TIMESTAMP = 17;
BSON.BSON_DATA_LONG = 18;
BSON.BSON_DATA_MIN_KEY = 0xff;
BSON.BSON_DATA_MAX_KEY = 0x7f;

// BSON BINARY DATA SUBTYPES
BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
Expand Down Expand Up @@ -88,7 +90,7 @@ BSON.calculateObjectSize = function(object) {
var name = keys[keysIndex++];
var value = currentObject[name];

if(value == null) {
if(value == null | value instanceof MinKey || value instanceof MaxKey) {
totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (1);
} else if(typeof value == 'string') {
totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(value, 'utf8') + 4 + 1 + 1);
Expand Down Expand Up @@ -300,9 +302,6 @@ BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object,
// Ajust index
index = index + 8;
} else {
debug(value.toString())
debug(long.toNumber().toString())

buffer[index + 3] = (lowBits >> 24) & 0xff;
buffer[index + 2] = (lowBits >> 16) & 0xff;
buffer[index + 1] = (lowBits >> 8) & 0xff;
Expand All @@ -327,21 +326,6 @@ BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object,
}
} else if(typeof value == 'number' || toString.call(value) === '[object Number]' ||
value instanceof Double) {

// } else if((typeof value == 'number' || toString.call(value) === '[object Number]') &&
// value == parseInt(value, 10) &&
// value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) {
//
// debug("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
// debug("====================== " + (typeof value == 'number'))
// debug("====================== " + (toString.call(value) === '[object Number]'))
// debug("====================== " + (value == parseInt(value, 10)))
// debug("====================== " + (value >= parseInt(BSON.JS_INT_MIN, 10)))
// debug("" + value + " = " + BSON.JS_INT_MIN)
// debug("" + value + " = " + BSON.JS_INT_MAX)
// debug(value.toString())
// debug(value.toString().match(/\./))

// Write the type
buffer[index++] = BSON.BSON_DATA_NUMBER;
// Write the name
Expand Down Expand Up @@ -663,7 +647,23 @@ BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object,
// Update index
index = index + size - 1;
// Write zero
buffer[index++] = 0;
buffer[index++] = 0;
} else if(value instanceof MinKey) {
// Write the type of either Array or object
buffer[index++] = BSON.BSON_DATA_MIN_KEY;
// Write the name
if(name != null) {
index = index + buffer.write(name, index, 'utf8') + 1;
buffer[index - 1] = 0;
}
} else if(value instanceof MaxKey) {
// Write the type of either Array or object
buffer[index++] = BSON.BSON_DATA_MAX_KEY;
// Write the name
if(name != null) {
index = index + buffer.write(name, index, 'utf8') + 1;
buffer[index - 1] = 0;
}
} else if(typeof value == 'object') {
// Write the type of either Array or object
buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT;
Expand Down Expand Up @@ -1135,30 +1135,11 @@ BSON.deserialize = function(data, options) {
if (type === BSON.BSON_DATA_LONG) {
// Convert to long
value = new Long(low_bits, high_bits);
// Convert to number


// Convert to number
if(value.lessThanOrEqual(JS_INT_MAX_LONG) && value.greaterThanOrEqual(JS_INT_MIN_LONG)) {
// debug("--------------------------------------------------------------- 0")
value = value.toNumber();
}


// convert back to number and compare the converted value with the original
// var value2 = value.toNumber();
//
// // if(value2 > )
//
// // If Long string representiation is the same return the normal value
// debug("========================== :: " + Long.MAX_VALUE)
// debug("========================== :: " + BSON.JS_INT_MAX)
// debug("========================== :: " + Math.pow(2, 53))
// debug("========================== :: " + value.toString())
// debug("========================== :: " + value2.toString())

// if(value.toString() === value2.toString()) {
// value = value2;
// }
} else {
value = new Timestamp(low_bits, high_bits);
}
Expand Down Expand Up @@ -1217,6 +1198,32 @@ BSON.deserialize = function(data, options) {

// Set object property
currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value;
} else if(type === BSON.BSON_DATA_MIN_KEY) {
// Read the null terminated string (indexof until first 0)
string_end_index = index;
while(data[string_end_index++] !== 0);
string_end_index = string_end_index - 1;

// Fetch the string name
string_name = data.toString('utf8', index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;

// Set object property
currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = new MinKey();
} else if(type === BSON.BSON_DATA_MAX_KEY) {
// Read the null terminated string (indexof until first 0)
string_end_index = index;
while(data[string_end_index++] !== 0);
string_end_index = string_end_index - 1;

// Fetch the string name
string_name = data.toString('utf8', index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;

// Set object property
currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = new MaxKey();
} else if(type === BSON.BSON_DATA_SYMBOL) {
// Read the null terminated string (indexof until first 0)
string_end_index = index;
Expand Down Expand Up @@ -1291,6 +1298,18 @@ Symbol.prototype.inspect = function() {
return this.value;
}

/**
* MinKey constructor
*
*/
function MinKey() {}

/**
* MaxKey constructor
*
*/
function MaxKey() {}

/**
* DBRef constructor.
*
Expand Down Expand Up @@ -1326,3 +1345,5 @@ exports.ObjectID = ObjectID;
exports.Long = Long;
exports.Timestamp = Timestamp;
exports.Double = Double;
exports.MinKey = MinKey;
exports.MaxKey = MaxKey;
17 changes: 17 additions & 0 deletions test/bson/bson_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ var testCase = require('../../deps/nodeunit').testCase,
Symbol = mongodb.Symbol,
DBRef = mongodb.DBRef,
Double = mongodb.Double,
MinKey = mongodb.MinKey,
MaxKey = mongodb.MaxKey,
BinaryParser = mongodb.BinaryParser;

// var m = require('../../lib/mongodb').pure();
Expand Down Expand Up @@ -1004,6 +1006,21 @@ var tests = testCase({
test.done();
},

'Should correctly serialize and deserialize MinKey and MaxKey values' : function(test) {
var doc = {
_id : new ObjectID("4e886e687ff7ef5e00000162"),
minKey : new MinKey(),
maxKey : new MaxKey()
}

var serialized_data = BSONSE.BSON.serialize(doc, false, true);
var doc2 = BSONSE.BSON.deserialize(serialized_data);
test.deepEqual(doc, doc2)
test.ok(doc2.minKey instanceof MinKey);
test.ok(doc2.maxKey instanceof MaxKey);
test.done();
},

// 'Should Correctly Function' : function(test) {
// var doc = {b:1, func:function() {
// this.b = 2;
Expand Down

0 comments on commit ce6419e

Please sign in to comment.