diff --git a/binding.gyp b/binding.gyp index 82bf76bd1..fba5763fa 100644 --- a/binding.gyp +++ b/binding.gyp @@ -17,14 +17,7 @@ ], }, "sources": [ - "src/objects/int64/int64.cc", - "src/util/data.cc", - "src/objects/database/database.cc", - "src/objects/statement/statement.cc", - "src/objects/transaction/transaction.cc", - "src/binder/binder.cc", - "src/multi-binder/multi-binder.cc", - "src/better_sqlite3.cc" + "src2/better_sqlite3.cpp" ] } ] diff --git a/package.json b/package.json index 511ffdff5..c2734bd44 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "pretest": "rm -r ./temp/ || true && mkdir ./temp/", "posttest": "rm -r ./temp/", "benchmark": "node benchmark", - "rebuild": "CI=true ./tools/build && node tools/install", + "rebuild": "CI=true ./tools/build && node tools/install" }, "license": "MIT", "keywords": [ diff --git a/src/objects/database/database.cc b/src/objects/database/database.cc index d14bfeace..4a4889c77 100644 --- a/src/objects/database/database.cc +++ b/src/objects/database/database.cc @@ -51,7 +51,7 @@ Database::~Database() { CloseHandles(); } -void Database::Init(v8::Local exports, v8::Local module) { +void Database::Init(v8::Local exports) { v8HandleScope; v8::Local t = Nan::New(New); diff --git a/src/objects/int64/int64.cc b/src/objects/int64/int64.cc index 51deaac15..1cb3114a1 100644 --- a/src/objects/int64/int64.cc +++ b/src/objects/int64/int64.cc @@ -18,7 +18,7 @@ Int64::Int64(sqlite3_int64 full) : Nan::ObjectWrap(), low = (int32_t)((uint32_t)(((sqlite3_uint64)full) & U32_in_U64)); high = (int32_t)((uint32_t)(((sqlite3_uint64)full) >> 32)); } -void Int64::Init(v8::Local exports, v8::Local module) { +void Int64::Init(v8::Local exports) { v8HandleScope; v8::Local t = Nan::New(New); diff --git a/src2/better_sqlite3.cpp b/src2/better_sqlite3.cpp new file mode 100644 index 000000000..6551e1ac5 --- /dev/null +++ b/src2/better_sqlite3.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include +#include +#include "objects/int64/int64.cpp" + +void RegisterModule(v8::Local exports, v8::Local module) { + v8::HandleScope scope(v8::Isolate::GetCurrent()); + + Int64::Init(exports); +} +NODE_MODULE(better_sqlite3, RegisterModule); diff --git a/src2/objects/int64/int64.cpp b/src2/objects/int64/int64.cpp new file mode 100644 index 000000000..08bc82664 --- /dev/null +++ b/src2/objects/int64/int64.cpp @@ -0,0 +1,130 @@ +inline v8::Local NEW_INTERNAL_STRING_FAST(const char* data) { + return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), reinterpret_cast(data), v8::NewStringType::kInternalized).ToLocalChecked(); +} +inline v8::Local StringFromLatin1(v8::Isolate* isolate, const char* data, int length) { + return v8::String::NewFromOneByte(isolate, reinterpret_cast(data), v8::NewStringType::kNormal, length).ToLocalChecked(); +} +inline v8::Local StringFromUtf8(v8::Isolate* isolate, const char* data, int length) { + return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal, length).ToLocalChecked(); +} +inline v8::Local InternalizedFromUtf8(v8::Isolate* isolate, const char* data, int length) { + return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kInternalized, length).ToLocalChecked(); +} + +const sqlite3_int64 MAX_SAFE = (sqlite3_int64)9007199254740991; +const sqlite3_int64 MIN_SAFE = (sqlite3_int64)-9007199254740991; +const sqlite3_uint64 U32_in_U64 = (sqlite3_uint64)0xffffffff; + +class Int64 : public node::ObjectWrap { +public: + explicit Int64(int32_t _low, int32_t _high) : node::ObjectWrap() { + low = _low; + high = _high; + full = (sqlite3_int64)((((sqlite3_uint64)((uint32_t)_high)) << 32) | (uint32_t)_low); + } + explicit Int64(sqlite3_int64 _full) : node::ObjectWrap() { + low = (int32_t)((uint32_t)(((sqlite3_uint64)_full) & U32_in_U64)); + high = (int32_t)((uint32_t)(((sqlite3_uint64)_full) >> 32)); + full = _full; + } + static void Init(v8::Local exports) { + v8::Local t = Nan::New(JS_new); + t->InstanceTemplate()->SetInternalFieldCount(1); + t->SetClassName(NEW_INTERNAL_STRING_FAST("Int64")); + + Nan::SetAccessor(t->InstanceTemplate(), NEW_INTERNAL_STRING_FAST("low"), JS_low); + Nan::SetAccessor(t->InstanceTemplate(), NEW_INTERNAL_STRING_FAST("high"), JS_high); + Nan::SetPrototypeMethod(t, "toString", JS_toString); + Nan::SetPrototypeMethod(t, "valueOf", JS_valueOf); + + constructor.Reset(exports->GetIsolate(), Nan::GetFunction(t).ToLocalChecked()); + constructorTemplate.Reset(exports->GetIsolate(), t); + + Nan::Set(exports, NEW_INTERNAL_STRING_FAST("Int64"), Nan::GetFunction(t).ToLocalChecked()); + } + + static inline v8::Local NewProperInteger(sqlite3_int64 value, bool safe_integers) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + if (safe_integers) { + FastConstructInt = &value; + return v8::Local::New(isolate, constructor)->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); + } + return v8::Number::New(isolate, static_cast(value)); + } + + static inline bool HasInstance(v8::Local value) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Local Int64Template = v8::Local::New(isolate, constructorTemplate); + return Int64Template->HasInstance(value); + } + + inline sqlite3_int64 GetValue() { + return full; + } + +private: + static v8::Persistent constructor; + static v8::Persistent constructorTemplate; + static sqlite3_int64* FastConstructInt; + + sqlite3_int64 full; + int32_t low; + int32_t high; + + static NAN_METHOD(JS_new) { + if (FastConstructInt != NULL) { + Int64* int64 = new Int64(*FastConstructInt); + FastConstructInt = NULL; + int64->Wrap(info.This()); + return info.GetReturnValue().Set(info.This()); + } + + int32_t low; + int32_t high; + + if (info.Length() < 1 || !info[0]->IsInt32()) { + info.GetIsolate()->ThrowException(v8::Exception::TypeError( + StringFromUtf8(info.GetIsolate(), "Expected arguemnt 1 to be a 32-bit signed integer", -1))); + return; + } + low = v8::Local::Cast(info[0])->Value(); + + if (info.Length() > 1) { + if (!info[1]->IsInt32()) { + info.GetIsolate()->ThrowException(v8::Exception::TypeError( + StringFromUtf8(info.GetIsolate(), "Expected arguemnt 2 to be a 32-bit signed integer", -1))); + return; + } + high = v8::Local::Cast(info[1])->Value(); + } else { + high = 0; + } + + Int64* int64 = new Int64(low, high); + int64->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + static NAN_GETTER(JS_low) { + info.GetReturnValue().Set(v8::Int32::New(info.GetIsolate(), node::ObjectWrap::Unwrap(info.This())->low)); + } + static NAN_GETTER(JS_high) { + info.GetReturnValue().Set(v8::Int32::New(info.GetIsolate(), node::ObjectWrap::Unwrap(info.This())->high)); + } + static NAN_METHOD(JS_toString) { + v8::Isolate* const isolate = info.GetIsolate(); + std::string string = std::to_string(static_cast(node::ObjectWrap::Unwrap(info.This())->full)); + info.GetReturnValue().Set(StringFromLatin1(isolate, string.c_str(), string.length())); + } + static NAN_METHOD(JS_valueOf) { + sqlite3_int64 full = node::ObjectWrap::Unwrap(info.This())->full; + if (full <= MAX_SAFE && full >= MIN_SAFE) { + info.GetReturnValue().Set(v8::Number::New(info.GetIsolate(), static_cast(full))); + } else { + info.GetReturnValue().Set(v8::Number::New(info.GetIsolate(), std::numeric_limits::quiet_NaN())); + } + } +}; + +sqlite3_int64* Int64::FastConstructInt = NULL; +v8::Persistent Int64::constructor; +v8::Persistent Int64::constructorTemplate; diff --git a/tools/build b/tools/build index 13bfae10b..510f9fb1a 100755 --- a/tools/build +++ b/tools/build @@ -1,3 +1,3 @@ #!/usr/bin/env bash set -e -./tools/lzz +./tools/lzz -hx hpp -sx cpp -d -k BETTER_SQLITE3 -hl -sl ./src2/better_sqlite3.lzz