From f31412859869831b4f0d93411f24aa36aa3173a1 Mon Sep 17 00:00:00 2001 From: Michael Phan-Ba Date: Sun, 19 Feb 2012 21:30:57 -0800 Subject: [PATCH] Add missing comparator source files --- src/binding/comparator.cc | 202 ++++++++++++++++++++++++++++++++++++++ src/binding/comparator.h | 46 +++++++++ 2 files changed, 248 insertions(+) create mode 100644 src/binding/comparator.cc create mode 100644 src/binding/comparator.h diff --git a/src/binding/comparator.cc b/src/binding/comparator.cc new file mode 100644 index 0000000..de8beeb --- /dev/null +++ b/src/binding/comparator.cc @@ -0,0 +1,202 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "comparator.h" +#include "helpers.h" + +using namespace std; + +namespace node_leveldb { + +PartitionedBitwiseComparator::PartitionedBitwiseComparator( + const vector< pair >& partitions) + : partitions_(partitions) +{ + stringstream name("node_leveldb.PartitionedBitwiseComparator(", + stringstream::out | stringstream::app); + name << partitions.size(); + + // encode name with partition configuration + vector< pair >::const_iterator it; + for (it = partitions.begin(); it < partitions.end(); ++it) { + name << "," << it->first << ":" << static_cast(it->second); + } + + name << ")"; + name_ = name.str(); +} + +const char* PartitionedBitwiseComparator::Name() const { + return name_.c_str(); +} + +int PartitionedBitwiseComparator::Compare( + const leveldb::Slice& a, const leveldb::Slice& b) const +{ + size_t start = 0; + size_t rem = min(a.size(), b.size()); + + bool reverse = false; + + vector< pair >::const_iterator it = partitions_.begin(); + for (it = partitions_.begin(); it < partitions_.end(); ++it) { + size_t len = it->first; + reverse = it->second; + + if (len <= 0 || len >= rem) break; + + // slice this partition + leveldb::Slice as = leveldb::Slice(a.data() + start, len); + leveldb::Slice bs = leveldb::Slice(b.data() + start, len); + + // compare partition + int comp = as.compare(bs); + if (comp != 0) return reverse ? -comp : comp; + + start += len; + rem -= len; + } + + leveldb::Slice as = leveldb::Slice(a.data() + start, a.size() - start); + leveldb::Slice bs = leveldb::Slice(b.data() + start, b.size() - start); + + // compare end + int comp = as.compare(bs); + return reverse ? -comp : comp; +} + +void PartitionedBitwiseComparator::FindShortestSeparator( + string* start, const leveldb::Slice& limit) const +{ + // Find length of common prefix + size_t end = min(start->size(), limit.size()); + size_t idx = 0; + while (idx < end && (*start)[idx] == limit[idx]) idx++; + + // Do not shorten if one string is a prefix of the other + if (idx >= end) return; + + // find sort direction + uint32_t next = 0; + bool reverse = false; + vector< pair >::const_iterator it = partitions_.begin(); + for (; next <= idx && it < partitions_.end(); ++it) { + next += it->first; + reverse = it->second; + } + + uint8_t byte = static_cast((*start)[idx]); + + if (reverse) { + if (byte > static_cast(0x00) && + byte - 1 > static_cast(limit[idx])) + { + (*start)[idx]--; + start->resize(idx + 1); + assert(Compare(*start, limit) < 0); + } + } else { + if (byte < static_cast(0xff) && + byte + 1 < static_cast(limit[idx])) + { + (*start)[idx]++; + start->resize(idx + 1); + assert(Compare(*start, limit) < 0); + } + } +} + +void PartitionedBitwiseComparator::FindShortSuccessor(string* key) const { + // Find first character that can be incremented + size_t n = key->size(); + + // find sort direction for diff_index + vector< pair >::const_iterator it = partitions_.begin(); + size_t next = 0; + bool reverse = false; + + for (size_t i = 0; i < n; ++i) { + + // find sort direction for diff_index + while (next <= i && it < partitions_.end()) { + next += it->first; + reverse = it->second; + ++it; + } + + const uint8_t byte = (*key)[i]; + if (reverse) { + if (byte != static_cast(0x00)) { + (*key)[i] = byte - 1; + key->resize(i + 1); + return; + } + } else { + if (byte != static_cast(0xff)) { + (*key)[i] = byte + 1; + key->resize(i + 1); + return; + } + } + } +} + +void PartitionedBitwiseComparator::Initialize(Handle target) { + HandleScope scope; + NODE_SET_METHOD(target, "createPartitionedBitwiseComparator", Create); +} + +static void UnrefComparator(Persistent object, void* parameter) { + assert(object->IsExternal()); + assert(External::Unwrap(object) == parameter); + leveldb::Comparator* comparator = static_cast(parameter); + delete comparator; + object.Dispose(); +} + +Handle PartitionedBitwiseComparator::Create(const Arguments& args) { + HandleScope scope; + + if (args.Length() != 1 || !args[0]->IsArray()) + return ThrowTypeError("Invalid arguments"); + + Local array = Array::Cast(*args[0]); + uint32_t len = array->Length(); + + if (len % 2 != 0) + return ThrowTypeError("Invalid arguments"); + + vector< pair > partitions; + + for (uint32_t i = 0; i < len; i += 2) { + if (array->Has(i) && array->Has(i + 1)) { + Local boundValue = array->Get(i); + Local reverseValue = array->Get(i + 1); + + if (!boundValue->IsUint32() || !reverseValue->IsBoolean()) + return ThrowTypeError("Invalid arguments"); + + uint32_t bound = boundValue->Uint32Value(); + bool reverse = reverseValue->BooleanValue(); + + partitions.push_back(pair(bound, reverse)); + } + } + + PartitionedBitwiseComparator* comparator = + new PartitionedBitwiseComparator(partitions); + + Local result = External::New(comparator); + Persistent weak = Persistent::New(result); + weak.MakeWeak(comparator, &UnrefComparator); + + return result; +} + +} // namespace node_leveldb diff --git a/src/binding/comparator.h b/src/binding/comparator.h new file mode 100644 index 0000000..1e9f260 --- /dev/null +++ b/src/binding/comparator.h @@ -0,0 +1,46 @@ +#ifndef NODE_LEVELDB_COMPARATOR_H_ +#define NODE_LEVELDB_COMPARATOR_H_ + +#include +#include + +#include +#include +#include +#include + +using namespace v8; +using namespace node; + +namespace node_leveldb { + +/** + + Partitioned bitwise comparator allows keys to be ordered in reverse by + partition. + + For example, the key abc123 could be bitwise ordered in normal order for + bytes 1-3 (abc) and in reverse for bytes 4-6 (123). + + */ + +class PartitionedBitwiseComparator : leveldb::Comparator { + public: + static void Initialize(Handle target); + static Handle Create(const Arguments& args); + + virtual const char* Name() const; + virtual int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const; + virtual void FindShortestSeparator(std::string* start, const leveldb::Slice& limit) const; + virtual void FindShortSuccessor(std::string* key) const; + + private: + PartitionedBitwiseComparator(const std::vector< std::pair >& partitions); + + std::string name_; + const std::vector< std::pair > partitions_; +}; + +} // node_leveldb + +#endif // NODE_LEVELDB_COMPARATOR_H_