susumu.yata
null+****@clear*****
Tue Dec 16 10:40:48 JST 2014
susumu.yata 2014-11-05 17:35:04 +0900 (Wed, 05 Nov 2014) New Revision: 06bc56eec16fa86086055f1699ddfc15cbb626c5 https://github.com/groonga/grnxx/commit/06bc56eec16fa86086055f1699ddfc15cbb626c5 Message: Enable DB and Table. Added files: include/grnxx/array.hpp include/grnxx/data_types/data_type.hpp include/grnxx/data_types/datum.hpp include/grnxx/data_types/record.hpp lib/grnxx/impl/column/base.cpp lib/grnxx/impl/column/base.hpp lib/grnxx/impl/column/scalar.hpp lib/grnxx/impl/column/scalar/Makefile.am lib/grnxx/impl/column/vector.hpp lib/grnxx/impl/column/vector/Makefile.am lib/grnxx/impl/cursor.hpp Copied files: lib/grnxx/impl/column/scalar/bool.cpp (from include/grnxx/features/Makefile.am) lib/grnxx/impl/column/scalar/geo_point.cpp (from include/grnxx/features/Makefile.am) lib/grnxx/impl/column/vector/bool.cpp (from include/grnxx/features/Makefile.am) Removed files: include/grnxx/data_types/scalar/row_id.hpp include/grnxx/data_types/vector/row_id.hpp include/grnxx/memory.hpp lib/grnxx/array.cpp lib/grnxx/impl/column/column_base.cpp lib/grnxx/impl/column/column_base.hpp Modified files: configure.ac include/grnxx/Makefile.am include/grnxx/column.hpp include/grnxx/cursor.hpp include/grnxx/data_types.hpp include/grnxx/data_types/Makefile.am include/grnxx/data_types/na.hpp include/grnxx/data_types/scalar.hpp include/grnxx/data_types/scalar/Makefile.am include/grnxx/data_types/scalar/bool.hpp include/grnxx/data_types/scalar/float.hpp include/grnxx/data_types/scalar/geo_point.hpp include/grnxx/data_types/scalar/int.hpp include/grnxx/data_types/scalar/text.hpp include/grnxx/data_types/vector.hpp include/grnxx/data_types/vector/Makefile.am include/grnxx/data_types/vector/bool.hpp include/grnxx/data_types/vector/float.hpp include/grnxx/data_types/vector/geo_point.hpp include/grnxx/data_types/vector/int.hpp include/grnxx/data_types/vector/text.hpp include/grnxx/db.hpp include/grnxx/features/Makefile.am include/grnxx/string.hpp include/grnxx/table.hpp lib/grnxx/Makefile.am lib/grnxx/cursor.cpp lib/grnxx/db.cpp lib/grnxx/impl/Makefile.am lib/grnxx/impl/column.hpp lib/grnxx/impl/column/Makefile.am lib/grnxx/impl/column/column.hpp lib/grnxx/impl/db.cpp lib/grnxx/impl/db.hpp lib/grnxx/impl/table.cpp lib/grnxx/impl/table.hpp test/Makefile.am test/test_array.cpp test/test_db.cpp test/test_table.cpp Renamed files: lib/grnxx/impl/column/scalar/bool.hpp (from lib/grnxx/impl/column/column_bool.hpp) lib/grnxx/impl/column/scalar/float.cpp (from lib/grnxx/impl/column/column_float.cpp) lib/grnxx/impl/column/scalar/float.hpp (from lib/grnxx/impl/column/column_float.hpp) lib/grnxx/impl/column/scalar/geo_point.hpp (from lib/grnxx/impl/column/column_geo_point.hpp) lib/grnxx/impl/column/scalar/int.cpp (from lib/grnxx/impl/column/column_int.cpp) lib/grnxx/impl/column/scalar/int.hpp (from lib/grnxx/impl/column/column_int.hpp) lib/grnxx/impl/column/scalar/text.cpp (from lib/grnxx/impl/column/column_text.cpp) lib/grnxx/impl/column/scalar/text.hpp (from lib/grnxx/impl/column/column_text.hpp) lib/grnxx/impl/column/vector/bool.hpp (from lib/grnxx/impl/column/column_vector_bool.hpp) lib/grnxx/impl/column/vector/float.cpp (from lib/grnxx/impl/column/column_vector_float.cpp) lib/grnxx/impl/column/vector/float.hpp (from lib/grnxx/impl/column/column_vector_float.hpp) lib/grnxx/impl/column/vector/geo_point.cpp (from lib/grnxx/impl/column/column_vector_geo_point.cpp) lib/grnxx/impl/column/vector/geo_point.hpp (from lib/grnxx/impl/column/column_vector_geo_point.hpp) lib/grnxx/impl/column/vector/int.cpp (from lib/grnxx/impl/column/column_vector_int.cpp) lib/grnxx/impl/column/vector/int.hpp (from lib/grnxx/impl/column/column_vector_int.hpp) lib/grnxx/impl/column/vector/text.cpp (from lib/grnxx/impl/column/column_vector_text.cpp) lib/grnxx/impl/column/vector/text.hpp (from lib/grnxx/impl/column/column_vector_text.hpp) Modified: configure.ac (+4 -0) =================================================================== --- configure.ac 2014-10-31 21:43:45 +0900 (1b98252) +++ configure.ac 2014-11-05 17:35:04 +0900 (b6756ab) @@ -58,6 +58,10 @@ AC_CONFIG_FILES([Makefile include/grnxx/features/Makefile lib/Makefile lib/grnxx/Makefile + lib/grnxx/impl/Makefile + lib/grnxx/impl/column/Makefile + lib/grnxx/impl/column/scalar/Makefile + lib/grnxx/impl/column/vector/Makefile src/Makefile test/Makefile benchmark/Makefile]) Modified: include/grnxx/Makefile.am (+8 -8) =================================================================== --- include/grnxx/Makefile.am 2014-10-31 21:43:45 +0900 (d491d1a) +++ include/grnxx/Makefile.am 2014-11-05 17:35:04 +0900 (1d9b0e1) @@ -3,19 +3,19 @@ SUBDIRS = \ features pkginclude_HEADERS = \ + array.hpp \ + column.hpp \ + cursor.hpp \ + data_types.hpp \ + db.hpp \ error.hpp \ features.hpp \ library.hpp \ - memory.hpp \ - string.hpp + string.hpp \ + table.hpp -# column.hpp \ -# cursor.hpp \ -# db.hpp \ # expression.hpp \ # index.hpp \ # merger.hpp \ # pipeline.hpp \ -# sorter.hpp \ -# table.hpp \ -# types.hpp +# sorter.hpp Added: include/grnxx/array.hpp (+349 -0) 100644 =================================================================== --- /dev/null +++ include/grnxx/array.hpp 2014-11-05 17:35:04 +0900 (69d4cd1) @@ -0,0 +1,349 @@ +#ifndef GRNXX_ARRAY_HPP +#define GRNXX_ARRAY_HPP + +#include <cstdlib> +#include <new> +#include <utility> + +namespace grnxx { + +template <typename T> +class ArrayCRef { + public: + using Value = T; + + ArrayCRef() = default; + ~ArrayCRef() = default; + + ArrayCRef(const ArrayCRef &) = default; + ArrayCRef &operator=(const ArrayCRef &) & = default; + + // Create a reference to an array. + ArrayCRef(const Value *values, size_t size) : values_(values), size_(size) {} + + // Create a reference to a part of "this". + ArrayCRef cref(size_t offset = 0) const { + return ArrayCRef(values_ + offset, size_ - offset); + } + // Create a reference to a part of "this". + ArrayCRef cref(size_t offset, size_t size) const { + return ArrayCRef(values_ + offset, size); + } + + // Return a reference to the "i"-th value. + const Value &get(size_t i) const { + return values_[i]; + } + + // Return a reference to the "i"-th value. + const Value &operator[](size_t i) const { + return values_[i]; + } + + // Return the number of values. + size_t size() const { + return size_; + } + + private: + const Value *values_; + size_t size_; +}; + +template <typename T> +class ArrayRef { + public: + using Value = T; + + ArrayRef() = default; + ~ArrayRef() = default; + + ArrayRef(const ArrayRef &) = default; + ArrayRef &operator=(const ArrayRef &) & = default; + + // Create a reference to an array. + ArrayRef(Value *values, size_t size) : values_(values), size_(size) {} + + // Create a reference to "this". + operator ArrayCRef<Value>() const { + return cref(); + } + + // Create a reference to a part of "this". + ArrayCRef<Value> cref(size_t offset = 0) const { + return ArrayCRef<Value>(values_ + offset, size_ - offset); + } + // Create a reference to a part of "this". + ArrayCRef<Value> cref(size_t offset, size_t size) const { + return ArrayCRef<Value>(values_ + offset, size); + } + + // Create a reference to a part of "this". + ArrayRef ref(size_t offset = 0) { + return ArrayRef(values_ + offset, size_ - offset); + } + // Create a reference to a part of "this". + ArrayRef ref(size_t offset, size_t size) { + return ArrayRef(values_ + offset, size); + } + + // Return the "i"-th value. + const Value &get(size_t i) const { + return values_[i]; + } + // Set the "i"-th value. + void set(size_t i, const Value &value) { + values_[i] = value; + } + // Set the "i"-th value. + void set(size_t i, Value &&value) { + values_[i] = std::move(value); + } + + // Return a reference to the "i"-th value. + Value &operator[](size_t i) { + return values_[i]; + } + // Return a reference to the "i"-th value. + const Value &operator[](size_t i) const { + return values_[i]; + } + + // Return the number of values. + size_t size() const { + return size_; + } + + private: + Value *values_; + size_t size_; +}; + +template <typename T> +class Array { + public: + using Value = T; + + Array() : buffer_(nullptr), size_(0), capacity_(0) {} + ~Array() { + std::free(buffer_); + } + + Array(const Array &) = delete; + Array &operator=(const Array &) & = delete; + + // Move the ownership of an array. + Array(Array &&array) + : buffer_(array.buffer_), + size_(array.size_), + capacity_(array.capacity_) { + array.buffer_ = nullptr; + array.size_ = 0; + array.capacity_ = 0; + } + // Move the ownership of an array. + Array &operator=(Array &&array) & { + std::free(buffer_); + buffer_ = array.buffer_; + size_ = array.size_; + capacity_ = array.capacity_; + array.buffer_ = nullptr; + array.size_ = 0; + array.capacity_ = 0; + return *this; + } + + // Create a reference to "this". + operator ArrayCRef<Value>() const { + return cref(); + } + + // Create a reference to a part of "this". + ArrayCRef<Value> cref(size_t offset = 0) const { + return ArrayCRef<Value>(data() + offset, size_ - offset); + } + // Create a reference to a part of "this". + ArrayCRef<Value> cref(size_t offset, size_t size) const { + return ArrayCRef<Value>(data() + offset, size); + } + + // Create a reference to a part of "this". + ArrayRef<Value> ref(size_t offset = 0) { + return ArrayRef<Value>(buffer() + offset, size_ - offset); + } + // Create a reference to a part of "this". + ArrayRef<Value> ref(size_t offset, size_t size) { + return ArrayRef<Value>(buffer() + offset, size); + } + + // Return a reference to the "i"-th value. + const Value &get(size_t i) const { + return data()[i]; + } + // Set the "i"-th value. + void set(size_t i, const Value &value) { + buffer()[i] = value; + } + // Set the "i"-th value. + void set(size_t i, Value &&value) { + buffer()[i] = std::move(value); + } + + // Return a reference to the "i"-th value. + Value &operator[](size_t i) { + return buffer()[i]; + } + // Return a reference to the "i"-th value. + const Value &operator[](size_t i) const { + return data()[i]; + } + + // Return a reference to the first value. + Value &front() { + return *buffer(); + } + // Return a reference to the first value. + const Value &front() const { + return *data(); + } + + // Return a reference to the last value. + Value &back() { + return buffer()[size_ - 1]; + } + // Return a reference to the last value. + const Value &back() const { + return data()[size_ - 1]; + } + + // Return a pointer to the buffer. + Value *buffer() { + return static_cast<Value *>(buffer_); + } + // Return a pointer to the contents. + const Value *data() const { + return static_cast<const Value *>(buffer_); + } + + // Return the number of values. + size_t size() const { + return size_; + } + // Return the number of values can be stored in the buffer. + size_t capacity() const { + return capacity_; + } + + // Reserve memory for at least "new_size" values. + // + // On failure, throws an exception. + void reserve(size_t new_size) { + if (new_size > capacity_) { + resize_buffer(new_size); + } + } + + // Resize "this". + // + // On failure, throws an exception. + void resize(size_t new_size) { + if (new_size > capacity_) { + resize_buffer(new_size); + } + for (size_t i = new_size; i < size_; ++i) { + buffer()[i].~Value(); + } + for (size_t i = size_; i < new_size; ++i) { + new (&buffer()[i]) Value; + } + size_ = new_size; + } + // Resize "this" and fill the new values with "value". + // + // On failure, throws an exception. + void resize(size_t new_size, const Value &value) { + if (new_size > capacity_) { + resize_buffer(new_size); + } + for (size_t i = new_size; i < size_; ++i) { + buffer()[i].~Value(); + } + for (size_t i = size_; i < new_size; ++i) { + new (&buffer()[i]) Value(value); + } + size_ = new_size; + } + + // Clear the contents. + void clear() { + for (size_t i = 0; i < size_; ++i) { + buffer()[i].~Value(); + } + size_ = 0; + } + + // Remove the "i"-th value. + void erase(size_t i) { + for (size_t j = i + 1; j < size_; ++j) { + buffer()[j - 1] = std::move(buffer()[j]); + } + buffer()[size_ - 1].~Value(); + --size_; + } + + // Append "value" to the end. + // + // On failure, throws an exception. + void push_back(const Value &value) { + if (size_ == capacity_) { + resize_buffer(size_ + 1); + } + new (&buffer()[size_]) Value(value); + ++size_; + } + // Append "value" to the end. + // + // On failure, throws an exception. + void push_back(Value &&value) { + if (size_ == capacity_) { + resize_buffer(size_ + 1); + } + new (&buffer()[size_]) Value(std::move(value)); + ++size_; + } + // Remove the last value. + void pop_back() { + buffer()[size_ - 1].~Value(); + --size_; + } + + private: + void *buffer_; + size_t size_; + size_t capacity_; + + // Resize the buffer for at least "new_size" values. + // + // Assumes that "new_size" is greater than "capacity_". + void resize_buffer(size_t new_size) { + size_t new_capacity = capacity_ * 2; + if (new_size > new_capacity) { + new_capacity = new_size; + } + size_t new_buffer_size = sizeof(Value) * new_capacity; + Value *new_buffer = static_cast<Value *>(std::malloc(new_buffer_size)); + if (!new_buffer) { + throw "Failed"; // TODO + } + for (size_t i = 0; i < size_; ++i) { + new (&new_buffer[i]) Value(std::move(buffer()[i])); + } + std::free(buffer_); + buffer_ = new_buffer; + capacity_ = new_capacity; + } +}; + +} // namespace grnxx + +#endif // GRNXX_ARRAY_HPP Modified: include/grnxx/column.hpp (+105 -92) =================================================================== --- include/grnxx/column.hpp 2014-10-31 21:43:45 +0900 (38a8a6c) +++ include/grnxx/column.hpp 2014-11-05 17:35:04 +0900 (2600868) @@ -1,10 +1,24 @@ #ifndef GRNXX_COLUMN_HPP #define GRNXX_COLUMN_HPP -#include "grnxx/types.hpp" +#include <memory> + +#include "grnxx/column.hpp" +#include "grnxx/cursor.hpp" +#include "grnxx/data_types.hpp" +#include "grnxx/string.hpp" namespace grnxx { +class Table; + +struct ColumnOptions { + // The referenced (parent) table. + String reference_table_name; + + ColumnOptions(); +}; + class Column { public: Column() = default; @@ -12,104 +26,103 @@ class Column { // Return the table. virtual Table *table() const = 0; // Return the name. - virtual StringCRef name() const = 0; + virtual String name() const = 0; // Return the data type. virtual DataType data_type() const = 0; - // Return the referenced (parent) table, or nullptr if the column is not a - // reference column. - virtual Table *ref_table() const = 0; - // Return whether the column has the key attribute or not. - virtual bool has_key_attribute() const = 0; - // Return the number of indexes. - virtual Int num_indexes() const = 0; - - // Create an index with "name", "index_type", and "index_options". - // - // On success, returns a pointer to the index. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - virtual Index *create_index( - Error *error, - const StringCRef &name, - IndexType type, - const IndexOptions &options = IndexOptions()) = 0; - - // Remove an index named "name". + // Return the reference table. + // If "this" is not a reference column, returns nullptr. + virtual Table *reference_table() const = 0; +// // Return whether the column has the key attribute or not. +// virtual bool is_key() const = 0; +// // Return the number of indexes. +// virtual size_t num_indexes() const = 0; + +// // Create an index with "name", "index_type", and "index_options". +// // +// // On success, returns a pointer to the index. +// // On failure, returns nullptr and stores error information into "*error" if +// // "error" != nullptr. +// virtual Index *create_index( +// Error *error, +// const String &name, +// IndexType type, +// const IndexOptions &options = IndexOptions()) = 0; + +// // Remove an index named "name". +// // +// // On success, returns true. +// // On failure, returns false and stores error information into "*error" if +// // "error" != nullptr. +// // +// // Note: Pointers to the removed index must not be used after deletion. +// virtual bool remove_index(Error *error, const String &name) = 0; + +// // Rename an index named "name" to "new_name". +// // +// // On success, returns true. +// // On failure, returns false and stores error information into "*error" if +// // "error" != nullptr. +// virtual bool rename_index(Error *error, +// const String &name, +// const String &new_name) = 0; + +// // Change the order of indexes. +// // +// // If "prev_name" is an empty string, moves an index named "name" to the +// // head. +// // If "name" == "prev_name", does nothing. +// // Otherwise, moves an index named "name" to next to an index named +// // "prev_name". +// // +// // On success, returns true. +// // On failure, returns false and stores error information into "*error" if +// // "error" != nullptr. +// virtual bool reorder_index(Error *error, +// const String &name, +// const String &prev_name) = 0; + +// // Get an index identified by "index_id". +// // +// // If "index_id" is invalid, the result is undefined. +// // +// // On success, returns a pointer to the index. +// // On failure, returns nullptr and stores error information into "*error" if +// // "error" != nullptr. +// virtual Index *get_index(Int index_id) const = 0; + +// // Find an index named "name". +// // +// // On success, returns a pointer to the index. +// // On failure, returns nullptr and stores error information into "*error" if +// // "error" != nullptr. +// virtual Index *find_index(Error *error, const String &name) const = 0; + + // Get a value associated with "row_id". // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. + // If "row_id" is invalid, stores N/A into "*datum". // - // Note: Pointers to the removed index must not be used after deletion. - virtual bool remove_index(Error *error, const StringCRef &name) = 0; - - // Rename an index named "name" to "new_name". - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool rename_index(Error *error, - const StringCRef &name, - const StringCRef &new_name) = 0; - - // Change the order of indexes. - // - // If "prev_name" is an empty string, moves an index named "name" to the - // head. - // If "name" == "prev_name", does nothing. - // Otherwise, moves an index named "name" to next to an index named - // "prev_name". - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool reorder_index(Error *error, - const StringCRef &name, - const StringCRef &prev_name) = 0; - - // Get an index identified by "index_id". - // - // If "index_id" is invalid, the result is undefined. - // - // On success, returns a pointer to the index. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - virtual Index *get_index(Int index_id) const = 0; - - // Find an index named "name". - // - // On success, returns a pointer to the index. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - virtual Index *find_index(Error *error, const StringCRef &name) const = 0; + // On failure, throws an exception. + virtual void get(Int row_id, Datum *datum) const = 0; // Set a value. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool set(Error *error, Int row_id, const Datum &datum) = 0; - - // Get a value. - // - // Stores a value identified by "row_id" into "*datum". - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool get(Error *error, Int row_id, Datum *datum) const = 0; - - // Check if "datum" exists in the column or not. - // - // If exists, returns true. - // Otherwise, returns false. - virtual bool contains(const Datum &datum) const = 0; - - // Find "datum" in the column. - // - // On success, returns the row ID of the matched value. - // On failure, returns NULL_ROW_ID. - virtual Int find_one(const Datum &datum) const = 0; + // On failure, throws an exception. + virtual void set(Int row_id, const Datum &datum) = 0; + +// // Check if "datum" exists in the column or not. +// // +// // If exists, returns true. +// // Otherwise, returns false. +// virtual bool contains(const Datum &datum) const = 0; + +// // Find "datum" in the column. +// // +// // On success, returns the row ID of the matched value. +// // On failure, returns NULL_ROW_ID. +// virtual Int find_one(const Datum &datum) const = 0; + + std::unique_ptr<Cursor> create_cursor( + const CursorOptions &options = CursorOptions()); protected: virtual ~Column() = default; Modified: include/grnxx/cursor.hpp (+33 -31) =================================================================== --- include/grnxx/cursor.hpp 2014-10-31 21:43:45 +0900 (5fba651) +++ include/grnxx/cursor.hpp 2014-11-05 17:35:04 +0900 (30dae7c) @@ -1,59 +1,61 @@ #ifndef GRNXX_CURSOR_HPP #define GRNXX_CURSOR_HPP -#include "grnxx/types.hpp" +#include <cstddef> + +#include "grnxx/array.hpp" +#include "grnxx/data_types.hpp" namespace grnxx { -struct CursorResult { - bool is_ok; - Int count; +enum CursorOrderType { + // The natural order (the ascending order in most cases). + CURSOR_REGULAR_ORDER, + // The reverse order (the descending order in most cases). + CURSOR_REVERSE_ORDER +}; + +struct CursorOptions { + // The first "offset" records are skipped (default: 0). + size_t offset; + + // At most "limit" records are read (default: numeric_limits<size_t>::max()). + size_t limit; + + // The order of records (default: REGULAR_ORDER). + CursorOrderType order_type; + + CursorOptions(); }; class Cursor { public: - virtual ~Cursor() {} - - // Return the associated table. - const Table *table() const { - return table_; - } + Cursor() = default; + virtual ~Cursor() = default; // Read the next records. // // Reads at most "max_count" records into "*records". // - // On success, returns true and the number of records read. - // On failure, returns false and the number of records read and stores error - // information into "*error" if "error" != nullptr. - virtual CursorResult read(Error *error, - Int max_count, - Array<Record> *records); + // On success, returns the number of records read. + // On failure, throws an exception. + virtual size_t read(size_t max_count, Array<Record> *records); // Read the next records. // // Reads at most "records.size()" records into "records". // - // On success, returns true and the number of records read. - // On failure, returns false and the number of records read and stores error - // information into "*error" if "error" != nullptr. - virtual CursorResult read(Error *error, - ArrayRef<Record> records) = 0; + // On success, returns the number of records read. + // On failure, throws an exception. + virtual size_t read(ArrayRef<Record> records) = 0; // Read all the remaining records. // // Reads records into "*records". // - // On success, returns true and the number of records read. - // On failure, returns false and the number of records read and stores error - // information into "*error" if "error" != nullptr. - virtual CursorResult read_all(Error *error, - Array<Record> *records); - - protected: - const Table *table_; - - explicit Cursor(const Table *table) : table_(table) {} + // On success, returns the number of records read. + // On failure, throws an exception. + virtual size_t read_all(Array<Record> *records); }; } // namespace grnxx Modified: include/grnxx/data_types.hpp (+4 -0) =================================================================== --- include/grnxx/data_types.hpp 2014-10-31 21:43:45 +0900 (906d8fb) +++ include/grnxx/data_types.hpp 2014-11-05 17:35:04 +0900 (3f5b701) @@ -1,6 +1,10 @@ #ifndef GRNXX_DATA_TYPES_HPP #define GRNXX_DATA_TYPES_HPP +#include "grnxx/data_types/data_type.hpp" +#include "grnxx/data_types/datum.hpp" +#include "grnxx/data_types/na.hpp" +#include "grnxx/data_types/record.hpp" #include "grnxx/data_types/scalar.hpp" #include "grnxx/data_types/vector.hpp" Modified: include/grnxx/data_types/Makefile.am (+3 -0) =================================================================== --- include/grnxx/data_types/Makefile.am 2014-10-31 21:43:45 +0900 (c055bfa) +++ include/grnxx/data_types/Makefile.am 2014-11-05 17:35:04 +0900 (392ca96) @@ -4,6 +4,9 @@ SUBDIRS = \ pkgincludedir = ${includedir}/${PACKAGE}/data_types pkginclude_HEADERS = \ + data_type.hpp \ + datum.hpp \ na.hpp \ + record.hpp \ scalar.hpp \ vector.hpp Added: include/grnxx/data_types/data_type.hpp (+33 -0) 100644 =================================================================== --- /dev/null +++ include/grnxx/data_types/data_type.hpp 2014-11-05 17:35:04 +0900 (6858b8f) @@ -0,0 +1,33 @@ +#ifndef GRNXX_DATA_TYPES_DATA_TYPE_HPP +#define GRNXX_DATA_TYPES_DATA_TYPE_HPP + +namespace grnxx { + +enum DataType { + // N/A. + NA_DATA, + // True or false. + BOOL_DATA, + // 64-bit signed integer. + INT_DATA, + // Double precision (64-bit) floating point number. + FLOAT_DATA, + // Latitude-longitude in milliseconds. + GEO_POINT_DATA, + // Byte string. + TEXT_DATA, + // Vector of Bool. + BOOL_VECTOR_DATA, + // Vector of Int. + INT_VECTOR_DATA, + // Vector of Float. + FLOAT_VECTOR_DATA, + // Vector of GeoPoint. + GEO_POINT_VECTOR_DATA, + // Vector of Text. + TEXT_VECTOR_DATA +}; + +} // namespace grnxx + +#endif // GRNXX_DATA_TYPES_DATA_TYPE_HPP Added: include/grnxx/data_types/datum.hpp (+220 -0) 100644 =================================================================== --- /dev/null +++ include/grnxx/data_types/datum.hpp 2014-11-05 17:35:04 +0900 (b97335a) @@ -0,0 +1,220 @@ +#ifndef GRNXX_TYPES_DATUM_HPP +#define GRNXX_TYPES_DATUM_HPP + +#include "grnxx/data_types/data_type.hpp" +#include "grnxx/data_types/na.hpp" +#include "grnxx/data_types/scalar.hpp" +#include "grnxx/data_types/vector.hpp" + +namespace grnxx { + +class Datum { + public: + Datum() : type_(NA_DATA), na_() {} + // TODO: User-defined destructor will be required. + ~Datum() = default; + + // Create a N/A object. + Datum(NA) : type_(NA_DATA), na_() {} + // Create a Bool object. + Datum(Bool value) : type_(BOOL_DATA), bool_(value) {} + // Create an Int object. + Datum(Int value) : type_(INT_DATA), int_(value) {} + // Create a Float object. + Datum(Float value) : type_(FLOAT_DATA), float_(value) {} + // Create a GeoPoint object. + Datum(GeoPoint value) : type_(GEO_POINT_DATA), geo_point_(value) {} + // Create a Text object. + Datum(const Text &value) : type_(TEXT_DATA), text_(value) {} + // Create a Vector<Bool> object. + Datum(const Vector<Bool> &value) + : type_(BOOL_VECTOR_DATA), + bool_vector_(value) {} + // Create a Vector<Int> object. + Datum(const Vector<Int> &value) + : type_(INT_VECTOR_DATA), + int_vector_(value) {} + // Create a Vector<Float> object. + Datum(const Vector<Float> &value) + : type_(FLOAT_VECTOR_DATA), + float_vector_(value) {} + // Create a Vector<GeoPoint> object. + Datum(const Vector<GeoPoint> &value) + : type_(GEO_POINT_VECTOR_DATA), + geo_point_vector_(value) {} + // Create a Vector<Text> object. + Datum(const Vector<Text> &value) + : type_(TEXT_VECTOR_DATA), + text_vector_(value) {} + + // Return the data type. + DataType type() const { + return type_; + } + + // Access the content as Bool. + const Bool &as_bool() const { + return bool_; + } + // Access the content as Int. + const Int &as_int() const { + return int_; + } + // Access the content as Float. + const Float &as_float() const { + return float_; + } + // Access the content as GeoPoint. + const GeoPoint &as_geo_point() const { + return geo_point_; + } + // Access the content as Text. + const Text &as_text() const { + return text_; + } + // Access the content as Vector<Bool>. + const Vector<Bool> &as_bool_vector() const { + return bool_vector_; + } + // Access the content as Vector<Int>. + const Vector<Int> &as_int_vector() const { + return int_vector_; + } + // Access the content as Vector<Float>. + const Vector<Float> &as_float_vector() const { + return float_vector_; + } + // Access the content as Vector<GeoPoint>. + const Vector<GeoPoint> &as_geo_point_vector() const { + return geo_point_vector_; + } + // Access the content as Vector<Text>. + const Vector<Text> &as_text_vector() const { + return text_vector_; + } + + // Access the content as Bool. + Bool &as_bool() { + return bool_; + } + // Access the content as Int. + Int &as_int() { + return int_; + } + // Access the content as Float. + Float &as_float() { + return float_; + } + // Access the content as GeoPoint. + GeoPoint &as_geo_point() { + return geo_point_; + } + // Access the content as Text. + Text &as_text() { + return text_; + } + // Access the content as Vector<Bool>. + Vector<Bool> &as_bool_vector() { + return bool_vector_; + } + // Access the content as Vector<Int>. + Vector<Int> &as_int_vector() { + return int_vector_; + } + // Access the content as Vector<Float>. + Vector<Float> &as_float_vector() { + return float_vector_; + } + // Access the content as Vector<GeoPoint>. + Vector<GeoPoint> &as_geo_point_vector() { + return geo_point_vector_; + } + // Access the content as Vector<Text>. + Vector<Text> &as_text_vector() { + return text_vector_; + } + + // Force the specified interpretation. + Bool force_bool() const { + return bool_; + } + Int force_int() const { + return int_; + } + Float force_float() const { + return float_; + } + GeoPoint force_geo_point() const { + return geo_point_; + } + Text force_text() const { + return text_; + } + Vector<Bool> force_bool_vector() const { + return bool_vector_; + } + Vector<Int> force_int_vector() const { + return int_vector_; + } + Vector<Float> force_float_vector() const { + return float_vector_; + } + Vector<GeoPoint> force_geo_point_vector() const { + return geo_point_vector_; + } + Vector<Text> force_text_vector() const { + return text_vector_; + } + + // Force the specified interpretation. + void force(Bool *value) const { + *value = bool_; + } + void force(Int *value) const { + *value = int_; + } + void force(Float *value) const { + *value = float_; + } + void force(GeoPoint *value) const { + *value = geo_point_; + } + void force(Text *value) const { + *value = text_; + } + void force(Vector<Bool> *value) const { + *value = bool_vector_; + } + void force(Vector<Int> *value) const { + *value = int_vector_; + } + void force(Vector<Float> *value) const { + *value = float_vector_; + } + void force(Vector<GeoPoint> *value) const { + *value = geo_point_vector_; + } + void force(Vector<Text> *value) const { + *value = text_vector_; + } + + private: + DataType type_; + union { + NA na_; + Bool bool_; + Int int_; + Float float_; + GeoPoint geo_point_; + Text text_; + Vector<Bool> bool_vector_; + Vector<Int> int_vector_; + Vector<Float> float_vector_; + Vector<GeoPoint> geo_point_vector_; + Vector<Text> text_vector_; + }; +}; + +} // namespace grnxx + +#endif // GRNXX_TYPES_DATUM_HPP Modified: include/grnxx/data_types/na.hpp (+5 -1) =================================================================== --- include/grnxx/data_types/na.hpp 2014-10-31 21:43:45 +0900 (b1fe63b) +++ include/grnxx/data_types/na.hpp 2014-11-05 17:35:04 +0900 (50d7f3d) @@ -1,10 +1,14 @@ #ifndef GRNXX_DATA_TYPES_NA_HPP #define GRNXX_DATA_TYPES_NA_HPP +#include "grnxx/data_types/data_type.hpp" + namespace grnxx { struct NA { - // TODO + constexpr DataType type() const { + return NA_DATA; + } }; } // namespace grnxx Added: include/grnxx/data_types/record.hpp (+24 -0) 100644 =================================================================== --- /dev/null +++ include/grnxx/data_types/record.hpp 2014-11-05 17:35:04 +0900 (882a253) @@ -0,0 +1,24 @@ +#ifndef GRNXX_DATA_TYPES_RECORD_HPP +#define GRNXX_DATA_TYPES_RECORD_HPP + +#include "grnxx/data_types/scalar/int.hpp" +#include "grnxx/data_types/scalar/float.hpp" + +namespace grnxx { + +struct Record { + Int row_id; + Float score; + + Record() = default; + ~Record() = default; + + Record(const Record &) = default; + Record &operator=(const Record &) & = default; + + Record(Int row_id, Float score) : row_id(row_id), score(score) {} +}; + +} // namespace grnxx + +#endif // GRNXX_DATA_TYPES_RECORD_HPP Modified: include/grnxx/data_types/scalar.hpp (+0 -1) =================================================================== --- include/grnxx/data_types/scalar.hpp 2014-10-31 21:43:45 +0900 (5aaf3ca) +++ include/grnxx/data_types/scalar.hpp 2014-11-05 17:35:04 +0900 (acebe7d) @@ -6,7 +6,6 @@ #include "grnxx/data_types/scalar/float.hpp" #include "grnxx/data_types/scalar/geo_point.hpp" #include "grnxx/data_types/scalar/int.hpp" -#include "grnxx/data_types/scalar/row_id.hpp" #include "grnxx/data_types/scalar/text.hpp" #endif // GRNXX_DATA_TYPES_SCALAR_HPP Modified: include/grnxx/data_types/scalar/Makefile.am (+0 -1) =================================================================== --- include/grnxx/data_types/scalar/Makefile.am 2014-10-31 21:43:45 +0900 (7f77c2d) +++ include/grnxx/data_types/scalar/Makefile.am 2014-11-05 17:35:04 +0900 (8b276e1) @@ -4,5 +4,4 @@ pkginclude_HEADERS = \ float.hpp \ geo_point.hpp \ int.hpp \ - row_id.hpp \ text.hpp Modified: include/grnxx/data_types/scalar/bool.hpp (+4 -0) =================================================================== --- include/grnxx/data_types/scalar/bool.hpp 2014-10-31 21:43:45 +0900 (233b2c6) +++ include/grnxx/data_types/scalar/bool.hpp 2014-11-05 17:35:04 +0900 (383616c) @@ -3,6 +3,7 @@ #include <cstdint> +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" namespace grnxx { @@ -19,6 +20,9 @@ class Bool { : value_(value ? true_value() : false_value()) {} explicit constexpr Bool(NA) : value_(na_value()) {} + constexpr DataType type() const { + return BOOL_DATA; + } constexpr uint8_t value() const { return value_; } Modified: include/grnxx/data_types/scalar/float.hpp (+4 -0) =================================================================== --- include/grnxx/data_types/scalar/float.hpp 2014-10-31 21:43:45 +0900 (be40c1f) +++ include/grnxx/data_types/scalar/float.hpp 2014-11-05 17:35:04 +0900 (092aa36) @@ -4,6 +4,7 @@ #include <cmath> #include <limits> +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" namespace grnxx { @@ -22,6 +23,9 @@ class Float { explicit constexpr Float(double value) : value_(value) {} explicit constexpr Float(NA) : value_(na_value()) {} + constexpr DataType type() const { + return FLOAT_DATA; + } constexpr double value() const { return value_; } Modified: include/grnxx/data_types/scalar/geo_point.hpp (+4 -0) =================================================================== --- include/grnxx/data_types/scalar/geo_point.hpp 2014-10-31 21:43:45 +0900 (ab55a61) +++ include/grnxx/data_types/scalar/geo_point.hpp 2014-11-05 17:35:04 +0900 (414bff0) @@ -4,6 +4,7 @@ #include <cstdint> #include <limits> +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" namespace grnxx { @@ -30,6 +31,9 @@ class GeoPoint { : latitude_(na_latitude()), longitude_(na_longitude()) {} + constexpr DataType type() const { + return GEO_POINT_DATA; + } constexpr int32_t latitude() const { return latitude_; } Modified: include/grnxx/data_types/scalar/int.hpp (+4 -0) =================================================================== --- include/grnxx/data_types/scalar/int.hpp 2014-10-31 21:43:45 +0900 (0c6de11) +++ include/grnxx/data_types/scalar/int.hpp 2014-11-05 17:35:04 +0900 (2230004) @@ -5,6 +5,7 @@ #include <limits> #include "grnxx/features.hpp" +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" namespace grnxx { @@ -21,6 +22,9 @@ class Int { explicit constexpr Int(int64_t value) : value_(value) {} explicit constexpr Int(NA) : value_(na_value()) {} + constexpr DataType type() const { + return INT_DATA; + } constexpr int64_t value() const { return value_; } Deleted: include/grnxx/data_types/scalar/row_id.hpp (+0 -62) 100644 =================================================================== --- include/grnxx/data_types/scalar/row_id.hpp 2014-10-31 21:43:45 +0900 (c3f6f4d) +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef GRNXX_DATA_TYPES_SCALAR_ROW_ID_HPP -#define GRNXX_DATA_TYPES_SCALAR_ROW_ID_HPP - -#include <cstdint> -#include <limits> - -#include "grnxx/data_types/na.hpp" - -namespace grnxx { - -class RowID { - public: - RowID() = default; - ~RowID() = default; - - constexpr RowID(const RowID &) = default; - RowID &operator=(const RowID &) = default; - - explicit constexpr RowID(uint64_t value) : value_(value) {} - explicit constexpr RowID(NA) : value_(na_value()) {} - - constexpr uint64_t value() const { - return value_; - } - - constexpr bool is_min() const { - return value_ == min_value(); - } - constexpr bool is_max() const { - return value_ == max_value(); - } - constexpr bool is_na() const { - return value_ == na_value(); - } - - static constexpr RowID min() { - return RowID(min_value()); - } - static constexpr RowID max() { - return RowID(max_value()); - } - static constexpr RowID na() { - return RowID(NA()); - } - - static constexpr uint64_t min_value() { - return 0; - } - static constexpr uint64_t max_value() { - return std::numeric_limits<uint64_t>::max() - 1; - } - static constexpr uint64_t na_value() { - return std::numeric_limits<uint64_t>::max(); - } - - private: - uint64_t value_; -}; - -} // namespace grnxx - -#endif // GRNXX_DATA_TYPES_SCALAR_ROW_ID_HPP Modified: include/grnxx/data_types/scalar/text.hpp (+4 -0) =================================================================== --- include/grnxx/data_types/scalar/text.hpp 2014-10-31 21:43:45 +0900 (2d18fde) +++ include/grnxx/data_types/scalar/text.hpp 2014-11-05 17:35:04 +0900 (dbb6667) @@ -4,6 +4,7 @@ #include <cstdint> #include <cstring> +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" namespace grnxx { @@ -23,6 +24,9 @@ class Text { constexpr Text(const char *data, size_t size) : data_(data), size_(size) {} explicit constexpr Text(NA) : data_(na_data()), size_(na_size()) {} + constexpr DataType type() const { + return TEXT_DATA; + } const char &operator[](size_t i) const { return data_[i]; } Modified: include/grnxx/data_types/vector.hpp (+0 -1) =================================================================== --- include/grnxx/data_types/vector.hpp 2014-10-31 21:43:45 +0900 (9084a5f) +++ include/grnxx/data_types/vector.hpp 2014-11-05 17:35:04 +0900 (04b35dd) @@ -6,7 +6,6 @@ #include "grnxx/data_types/vector/float.hpp" #include "grnxx/data_types/vector/geo_point.hpp" #include "grnxx/data_types/vector/int.hpp" -#include "grnxx/data_types/vector/row_id.hpp" #include "grnxx/data_types/vector/text.hpp" #endif // GRNXX_DATA_TYPES_VECTOR_HPP Modified: include/grnxx/data_types/vector/Makefile.am (+0 -1) =================================================================== --- include/grnxx/data_types/vector/Makefile.am 2014-10-31 21:43:45 +0900 (73c2290) +++ include/grnxx/data_types/vector/Makefile.am 2014-11-05 17:35:04 +0900 (8e7a423) @@ -4,5 +4,4 @@ pkginclude_HEADERS = \ float.hpp \ geo_point.hpp \ int.hpp \ - row_id.hpp \ text.hpp Modified: include/grnxx/data_types/vector/bool.hpp (+1 -0) =================================================================== --- include/grnxx/data_types/vector/bool.hpp 2014-10-31 21:43:45 +0900 (affd198) +++ include/grnxx/data_types/vector/bool.hpp 2014-11-05 17:35:04 +0900 (d317c00) @@ -1,6 +1,7 @@ #ifndef GRNXX_DATA_TYPES_VECTOR_BOOL_HPP #define GRNXX_DATA_TYPES_VECTOR_BOOL_HPP +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" #include "grnxx/data_types/scalar/bool.hpp" Modified: include/grnxx/data_types/vector/float.hpp (+1 -0) =================================================================== --- include/grnxx/data_types/vector/float.hpp 2014-10-31 21:43:45 +0900 (687cd64) +++ include/grnxx/data_types/vector/float.hpp 2014-11-05 17:35:04 +0900 (effc7d3) @@ -1,6 +1,7 @@ #ifndef GRNXX_DATA_TYPES_VECTOR_FLOAT_HPP #define GRNXX_DATA_TYPES_VECTOR_FLOAT_HPP +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" #include "grnxx/data_types/scalar/float.hpp" Modified: include/grnxx/data_types/vector/geo_point.hpp (+1 -0) =================================================================== --- include/grnxx/data_types/vector/geo_point.hpp 2014-10-31 21:43:45 +0900 (aea0cd0) +++ include/grnxx/data_types/vector/geo_point.hpp 2014-11-05 17:35:04 +0900 (1c9d9e0) @@ -1,6 +1,7 @@ #ifndef GRNXX_DATA_TYPES_VECTOR_GEO_POINT_HPP #define GRNXX_DATA_TYPES_VECTOR_GEO_POINT_HPP +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" #include "grnxx/data_types/scalar/geo_point.hpp" Modified: include/grnxx/data_types/vector/int.hpp (+1 -0) =================================================================== --- include/grnxx/data_types/vector/int.hpp 2014-10-31 21:43:45 +0900 (9457fd0) +++ include/grnxx/data_types/vector/int.hpp 2014-11-05 17:35:04 +0900 (892cc6c) @@ -1,6 +1,7 @@ #ifndef GRNXX_DATA_TYPES_VECTOR_INT_HPP #define GRNXX_DATA_TYPES_VECTOR_INT_HPP +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/na.hpp" #include "grnxx/data_types/scalar/int.hpp" Deleted: include/grnxx/data_types/vector/row_id.hpp (+0 -20) 100644 =================================================================== --- include/grnxx/data_types/vector/row_id.hpp 2014-10-31 21:43:45 +0900 (8ccc280) +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef GRNXX_DATA_TYPES_VECTOR_ROW_ID_HPP -#define GRNXX_DATA_TYPES_VECTOR_ROW_ID_HPP - -#include "grnxx/data_types/na.hpp" -#include "grnxx/data_types/scalar/row_id.hpp" - -namespace grnxx { - -template <typename T> class Vector; - -template <> -class Vector<RowID> { - // TODO -}; - -using RowIDVector = Vector<RowID>; - -} // namespace grnxx - -#endif // GRNXX_DATA_TYPES_VECTOR_ROW_ID_HPP Modified: include/grnxx/data_types/vector/text.hpp (+1 -1) =================================================================== --- include/grnxx/data_types/vector/text.hpp 2014-10-31 21:43:45 +0900 (e965152) +++ include/grnxx/data_types/vector/text.hpp 2014-11-05 17:35:04 +0900 (189ca22) @@ -1,7 +1,7 @@ #ifndef GRNXX_DATA_TYPES_VECTOR_TEXT_HPP #define GRNXX_DATA_TYPES_VECTOR_TEXT_HPP -#include "grnxx/data_types/na.hpp" +#include "grnxx/data_types/data_type.hpp" #include "grnxx/data_types/scalar/text.hpp" namespace grnxx { Modified: include/grnxx/db.hpp (+32 -54) =================================================================== --- include/grnxx/db.hpp 2014-10-31 21:43:45 +0900 (53c94d6) +++ include/grnxx/db.hpp 2014-11-05 17:35:04 +0900 (d1e3be2) @@ -1,45 +1,41 @@ #ifndef GRNXX_DB_HPP #define GRNXX_DB_HPP -#include "grnxx/types.hpp" +#include <memory> + +#include "grnxx/string.hpp" +#include "grnxx/table.hpp" namespace grnxx { +struct DBOptions { +}; + class DB { public: DB() = default; virtual ~DB() = default; // Return the number of tables. - virtual Int num_tables() const = 0; + virtual size_t num_tables() const = 0; - // Create a table with "name" and "options". + // Create a table. // // On success, returns a pointer to the table. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. + // On failure, throws an exception. virtual Table *create_table( - Error *error, - const StringCRef &name, + const String &name, const TableOptions &options = TableOptions()) = 0; // Remove a table named "name". // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - // - // Note: Pointers to the removed table must not be used after deletion. - virtual bool remove_table(Error *error, const StringCRef &name) = 0; + // On failure, throws an exception. + virtual void remove_table(const String &name) = 0; // Rename a table named "name" to "new_name". // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool rename_table(Error *error, - const StringCRef &name, - const StringCRef &new_name) = 0; + // On failure, throws an exception. + virtual void rename_table(const String &name, const String &new_name) = 0; // Change the order of tables. // @@ -48,28 +44,19 @@ class DB { // Otherwise, moves a table named "name" to next to a table named // "prev_name". // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool reorder_table(Error *error, - const StringCRef &name, - const StringCRef &prev_name) = 0; - - // Get a table identified by "table_id". - // - // If "table_id" is invalid, the result is undefined. + // On failure, throws an exception. + virtual void reorder_table(const String &name, const String &prev_name) = 0; + + // Return the "i"-th table. // - // On success, returns a pointer to the table. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - virtual Table *get_table(Int table_id) const = 0; + // If "i" >= "num_tables()", the behavior is undefined. + virtual Table *get_table(size_t table_id) const = 0; // Find a table named "name". // - // On success, returns a pointer to the table. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - virtual Table *find_table(Error *error, const StringCRef &name) const = 0; + // If found, returns a pointer to the table. + // If not found, returns nullptr. + virtual Table *find_table(const String &name) const = 0; // TODO: Not supported yet. // @@ -78,11 +65,8 @@ class DB { // If "path" is nullptr or an empty string, saves the database into its // associated file. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool save(Error *error, - const StringCRef &path, + // On failure, throws an exception. + virtual void save(const String &path, const DBOptions &options = DBOptions()) const = 0; }; @@ -93,22 +77,16 @@ class DB { // TODO: A named database is not supoprted yet. // // On success, returns a pointer to the database. -// On failure, returns nullptr and stores error information into "*error" if -// "error" != nullptr. -unique_ptr<DB> open_db(Error *error, - const StringCRef &path, - const DBOptions &options = DBOptions()); +// On failure, throws an exception. +std::unique_ptr<DB> open_db(const String &path, + const DBOptions &options = DBOptions()); // TODO: Not supported yet. // -// Remove a database identified by "path". +// Remove a database. // -// On success, returns true. -// On failure, returns false and stores error information into "*error" if -// "error" != nullptr. -bool remove_db(Error *error, - const StringCRef &path, - const DBOptions &options = DBOptions()); +// On failure, throws an exception. +void remove_db(const String &path, const DBOptions &options = DBOptions()); } // namespace grnxx Modified: include/grnxx/features/Makefile.am (+6 -0) =================================================================== --- include/grnxx/features/Makefile.am 2014-10-31 21:43:45 +0900 (e69de29) +++ include/grnxx/features/Makefile.am 2014-11-05 17:35:04 +0900 (c8b0f70) @@ -0,0 +1,6 @@ +pkgincludedir = ${includedir}/${PACKAGE}/features +pkginclude_HEADERS = \ + compiler.hpp \ + cpu.hpp \ + functions.hpp \ + os.hpp Deleted: include/grnxx/memory.hpp (+0 -16) 100644 =================================================================== --- include/grnxx/memory.hpp 2014-10-31 21:43:45 +0900 (055f59d) +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef GRNXX_MEMORY_HPP -#define GRNXX_MEMORY_HPP - -#include <memory> - -namespace grnxx { - -// Smart pointer. -using std::unique_ptr; - -// An object to make memory allocation (new) return nullptr on failure. -using std::nothrow; - -} // namespace grnxx - -#endif // GRNXX_MEMORY_HPP Modified: include/grnxx/string.hpp (+9 -5) =================================================================== --- include/grnxx/string.hpp 2014-10-31 21:43:45 +0900 (a9299fe) +++ include/grnxx/string.hpp 2014-11-05 17:35:04 +0900 (cb26266) @@ -36,7 +36,7 @@ class String { return *this; } - // Create a reference to "string". + // Create a reference to a null-terminated string. // // If "string" == nullptr, the behavior is undefined. String(const char *string) @@ -49,8 +49,12 @@ class String { size_(size), capacity_(0) {} // Create an instance. + // + // On failure, throws an exception. explicit String(size_t size); // Create an instance filled with "byte". + // + // On failure, throws an exception. String(size_t size, char byte); // Create a reference to a substring. @@ -137,7 +141,7 @@ class String { size_t size() const { return size_; } - // Return the size of the internal buffer. + // Return the buffer size. size_t capacity() const { return capacity_; } @@ -179,7 +183,7 @@ class String { } size_ = new_size; } - // Resize the string and fill the new space with "byte". + // Resize the string and fill the new bytes with "byte". // // On failure, throws an exception. void resize(size_t new_size, char byte) { @@ -416,14 +420,14 @@ class String { size_t size_; size_t capacity_; - // Resize the internal buffer for at least "new_size". + // Resize the buffer for at least "new_size". // // Assumes that "new_size" is greater than "capacity_". // // On failure, throws an exception. void resize_buffer(size_t new_size); - // Resize the internal buffer and append a part of "this". + // Resize the buffer and append a part of "this". // // On failure, throws an exception. void append_overlap(const char *data, size_t size); Modified: include/grnxx/table.hpp (+70 -97) =================================================================== --- include/grnxx/table.hpp 2014-10-31 21:43:45 +0900 (2dbf2f3) +++ include/grnxx/table.hpp 2014-11-05 17:35:04 +0900 (6ff4c56) @@ -1,11 +1,20 @@ #ifndef GRNXX_TABLE_HPP #define GRNXX_TABLE_HPP -#include "grnxx/name.hpp" -#include "grnxx/types.hpp" +#include <memory> + +#include "grnxx/column.hpp" +#include "grnxx/cursor.hpp" +#include "grnxx/data_types.hpp" +#include "grnxx/string.hpp" namespace grnxx { +class DB; + +struct TableOptions { +}; + class Table { public: Table() = default; @@ -13,44 +22,39 @@ class Table { // Return the owner DB. virtual DB *db() const = 0; // Return the name. - virtual StringCRef name() const = 0; + virtual String name() const = 0; // Return the number of columns. - virtual Int num_columns() const = 0; + virtual size_t num_columns() const = 0; // Return the key column, or nullptr if the table has no key column. virtual Column *key_column() const = 0; // Return the number of rows. - virtual Int num_rows() const = 0; + virtual size_t num_rows() const = 0; // Return the maximum row ID. virtual Int max_row_id() const = 0; + // Return whether "this" is empty or not. + virtual bool is_empty() const = 0; + // Return whether or not there are invalid records before the last record. + virtual bool is_full() const = 0; // Create a column with "name", "data_type", and "options". // // On success, returns a pointer to the column. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. + // On failure, throws an exception. virtual Column *create_column( - Error *error, - const StringCRef &name, + const String &name, DataType data_type, const ColumnOptions &options = ColumnOptions()) = 0; // Remove a column named "name". // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - // - // Note: Pointers to the removed column must not be used after deletion. - virtual bool remove_column(Error *error, const StringCRef &name) = 0; + // On failure, throws an exception. + virtual void remove_column(const String &name) = 0; // Rename a column named "name" to "new_name". // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool rename_column(Error *error, - const StringCRef &name, - const StringCRef &new_name) = 0; + // On failure, throws an exception. + virtual void rename_column(const String &name, + const String &new_name) = 0; // Change the order of columns. // @@ -60,115 +64,84 @@ class Table { // Otherwise, moves a column named "name" to next to a column named // "prev_name". // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool reorder_column(Error *error, - const StringCRef &name, - const StringCRef &prev_name) = 0; + // On failure, throws an exception. + virtual void reorder_column(const String &name, + const String &prev_name) = 0; - // Get a column identified by "column_id". + // Get the "i"-th column. // - // If "column_id" is invalid, the result is undefined. + // If "i" >= "num_columns", the behavior is undefined. // // On success, returns a pointer to the column. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - virtual Column *get_column(Int column_id) const = 0; + virtual Column *get_column(size_t column_id) const = 0; // Find a column named "name". // - // On success, returns a pointer to the column. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - virtual Column *find_column(Error *error, const StringCRef &name) const = 0; + // If found, returns a pointer to the column. + // If not found, returns nullptr. + virtual Column *find_column(const String &name) const = 0; - // Set the key attribute to the column named "name". + // Set a key column. // // Fails if the table already has a key column. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool set_key_column(Error *error, const StringCRef &name) = 0; + // On failure, throws an exception. + virtual void set_key_column(const String &name) = 0; - // Unset the key attribute of the key column. + // Unset a key column. // // Fails if the table does not have a key column. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool unset_key_column(Error *error) = 0; + // On failure, throws an exception. + virtual void unset_key_column() = 0; // Insert a row. // - // If "request_row_id" specifies an unused row ID, uses the row ID. - // If the table has a key column, "key" is used as the key of the new row. - // If "request_row_id" == NULL_ROW_ID, an unused row ID or max_row_id() + 1 - // is allocated for the new row. + // Fails if "key" is invalid. // - // Fails if "request_row_id" specifies an existing row. - // Fails if the table has a key column and "key" is invalid. + // On success, returns the row ID. + // On failure, throws an exception. + virtual Int insert_row(const Datum &key = NA()) = 0; + + // Find or insert a row. // - // On success, stores the inserted row ID into "*result_row_id". - // On failure, if "request_row_id" or "key" matches an existing row, - // stores the matched row ID into "*result_row_id". + // If "key" does not exist, insert a row with "key". + // If "inserted" != nullptr, stores whether inserted or not into "*inserted". // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool insert_row(Error *error, - Int request_row_id, - const Datum &key, - Int *result_row_id) = 0; + // On success, returns the row ID. + // On failure, throws an exception. + virtual Int find_or_insert_row(const Datum &key, + bool *inserted = nullptr) = 0; - // Remove a row identified by "row_id". + // Insert a row. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool remove_row(Error *error, Int row_id) = 0; - - // Check the validity of a row. + // Fails if "row_id" specifies an existing row. // - // Returns true if "row_id" specifies a row in use. - // Otherwise, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool test_row(Error *error, Int row_id) const = 0; + // On failure, throws an exception. + virtual void insert_row_at(Int row_id, const Datum &key = NA()) = 0; - // Find a row identified by "key". + // Remove a row. // - // Fails if the table does not have a key column. + // On failure, throws an exception. + virtual void remove_row(Int row_id) = 0; + + // Return whether a row is valid or not. + virtual bool test_row(Int row_id) const = 0; + + // Find a row with "key". // - // On success, returns the row ID. - // On failure, returns NULL_ROW_ID and stores error information into - // "*error" if "error" != nullptr. - virtual Int find_row(Error *error, const Datum &key) const = 0; + // If found, returns the row ID. + // If not found, returns N/A. + // On failure, throws an exception. + virtual Int find_row(const Datum &key) const = 0; // Create a cursor to get records. // // On success, returns a pointer to the cursor. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - virtual unique_ptr<Cursor> create_cursor( - Error *error, + // On failure, throws an exception. + virtual std::unique_ptr<Cursor> create_cursor( const CursorOptions &options = CursorOptions()) const = 0; - // TODO: Grouping (drilldown). - // - // 分類器を作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - オプションが不正である. - // - リソースが確保できない. -// virtual unique_ptr<Grouper> create_grouper( -// Error *error, -// unique_ptr<Expression> &&expression, -// const GrouperOptions &options = GrouperOptions()) const = 0; - protected: virtual ~Table() = default; }; Modified: lib/grnxx/Makefile.am (+7 -11) =================================================================== --- lib/grnxx/Makefile.am 2014-10-31 21:43:45 +0900 (97d412a) +++ lib/grnxx/Makefile.am 2014-11-05 17:35:04 +0900 (571f477) @@ -1,29 +1,25 @@ -#SUBDIRS = \ -# impl +SUBDIRS = \ + impl lib_LTLIBRARIES = libgrnxx.la -#libgrnxx_la_LIBADD = \ -# impl/libgrnxx_impl.la +libgrnxx_la_LIBADD = \ + impl/libgrnxx_impl.la libgrnxx_la_LDFLAGS = @AM_LTLDFLAGS@ libgrnxx_la_SOURCES = \ - error.cpp \ + cursor.cpp \ + db.cpp \ library.cpp \ string.cpp -# array.cpp \ -# cursor.cpp \ -# db.cpp \ -# error.cpp \ # expression.cpp \ # index.cpp \ # merger.cpp \ # name.cpp \ # pipeline.cpp \ -# sorter.cpp \ -# types.cpp +# sorter.cpp libgrnxx_includedir = ${includedir}/grnxx libgrnxx_include_HEADERS = \ Deleted: lib/grnxx/array.cpp (+0 -48) 100644 =================================================================== --- lib/grnxx/array.cpp 2014-10-31 21:43:45 +0900 (22b1a43) +++ /dev/null @@ -1,48 +0,0 @@ -#include "grnxx/types.hpp" - -namespace grnxx { - -void ArrayErrorReporter::report_memory_error(Error *error) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); -} - -bool Array<Bool>::resize_blocks(Error *error, Int new_size) { - Int new_capacity = capacity_ * 2; - if (new_size > new_capacity) { - new_capacity = (new_size + 63) & ~Int(63); - } - unique_ptr<Block[]> new_blocks(new (nothrow) Block[new_capacity / 64]); - if (!new_blocks) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return false; - } - Int num_valid_blocks = (size_ + 63) / 64; - for (Int i = 0; i < num_valid_blocks; ++i) { - new_blocks[i] = blocks_[i]; - } - blocks_ = std::move(new_blocks); - capacity_ = new_capacity; - return true; -} - -bool Array<Record>::resize_buf(Error *error, Int new_size) { - Int new_capacity = capacity_ * 2; - if (new_size > new_capacity) { - new_capacity = new_size; - } - Int new_buf_size = sizeof(Value) * new_capacity; - unique_ptr<char[]> new_buf(new (nothrow) char[new_buf_size]); - if (!new_buf) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return false; - } - Value *new_values = reinterpret_cast<Value *>(new_buf.get()); - for (Int i = 0; i < size_; ++i) { - new (&new_values[i]) Value(std::move(data()[i])); - } - buf_ = std::move(new_buf); - capacity_ = new_capacity; - return true; -} - -} // namespace grnxx Modified: lib/grnxx/cursor.cpp (+41 -45) =================================================================== --- lib/grnxx/cursor.cpp 2014-10-31 21:43:45 +0900 (d89d5cc) +++ lib/grnxx/cursor.cpp 2014-11-05 17:35:04 +0900 (f52fd12) @@ -1,79 +1,75 @@ #include "grnxx/cursor.hpp" +#include <limits> + namespace grnxx { namespace { -constexpr Int CURSOR_BLOCK_SIZE = 1024; +constexpr size_t CURSOR_BLOCK_SIZE = 1024; } // namespace -CursorResult Cursor::read(Error *error, - Int max_count, - Array<Record> *records) { - if (max_count < 0) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid argument"); - return { false, 0 }; - } else if (max_count == 0) { - return read(error, records->ref(0, 0)); +CursorOptions::CursorOptions() + : offset(0), + limit(std::numeric_limits<size_t>::max()), + order_type(CURSOR_REGULAR_ORDER) {} + +size_t Cursor::read(size_t max_count, Array<Record> *records) { + if (max_count == 0) { + return 0; } - Int offset = records->size(); - if (offset > (numeric_limits<Int>::max() - max_count)) { + size_t offset = records->size(); + if (offset > (std::numeric_limits<size_t>::max() - max_count)) { // Reduce "max_count" to avoid overflow. - max_count = numeric_limits<Int>::max() - offset; + max_count = std::numeric_limits<size_t>::max() - offset; } - Int next_size = offset + max_count; + size_t next_size = offset + max_count; if (next_size <= records->capacity()) { - // There are enough space for requested records. - records->resize(nullptr, next_size); - auto result = read(error, records->ref(offset, max_count)); - records->resize(nullptr, offset + result.count); - return result; + // There is enough space to store requested records. + records->resize(next_size); + size_t count = read(records->ref(offset, max_count)); + records->resize(offset + count); + return count; } // Read the first block. - Int block_size = max_count; + size_t block_size = max_count; if (block_size > CURSOR_BLOCK_SIZE) { block_size = CURSOR_BLOCK_SIZE; } - if (!records->resize(error, offset + block_size)) { - return { false, 0 }; - } - auto result = read(error, records->ref(offset, block_size)); - if (result.count != block_size) { - records->resize(nullptr, offset + result.count); - } - if (!result.is_ok || (result.count == 0)) { - return result; + records->resize(offset + block_size); + size_t count = read(records->ref(offset, block_size)); + if (count != block_size) { + records->resize(offset + count); + if (count == 0) { + return 0; + } } // Read the remaining blocks. - while (result.count < max_count) { - block_size = max_count - result.count; + while (count < max_count) { + block_size = max_count - count; if (block_size > CURSOR_BLOCK_SIZE) { block_size = CURSOR_BLOCK_SIZE; } - Int this_offset = offset + result.count; - if (!records->resize(error, this_offset + block_size)) { - result.is_ok = false; - return result; - } - auto this_result = read(error, records->ref(this_offset, block_size)); - if (this_result.count != block_size) { - records->resize(nullptr, this_offset + this_result.count); + size_t this_offset = offset + count; + records->resize(this_offset + block_size); + size_t this_count = read(records->ref(this_offset, block_size)); + if (this_count != block_size) { + records->resize(this_offset + this_count); } - result.is_ok = this_result.is_ok; - result.count += this_result.count; - if (!this_result.is_ok || (this_result.count == 0)) { - return result; + count += this_count; + if (this_count == 0) { + return count; } } - return result; + return count; } -CursorResult Cursor::read_all(Error *error, Array<Record> *records) { - return read(error, numeric_limits<Int>::max(), records); +size_t Cursor::read_all(Array<Record> *records) { + return read(std::numeric_limits<size_t>::max(), records); } } // namespace grnxx Modified: lib/grnxx/db.cpp (+9 -16) =================================================================== --- lib/grnxx/db.cpp 2014-10-31 21:43:45 +0900 (6a8599c) +++ lib/grnxx/db.cpp 2014-11-05 17:35:04 +0900 (97e70ba) @@ -1,29 +1,22 @@ #include "grnxx/db.hpp" +#include <new> + #include "grnxx/impl/db.hpp" namespace grnxx { -unique_ptr<DB> open_db(Error *error, - const StringCRef &path, - const DBOptions &) { +std::unique_ptr<DB> open_db(const String &path, const DBOptions &) try { if (path.size() != 0) { - // TODO: Named DB is not supported yet. - GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet"); - return nullptr; - } - unique_ptr<impl::DB> db(new (nothrow) impl::DB); - if (!db) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; + throw "Not supported yet"; // TODO } - return unique_ptr<DB>(db.release()); + return std::unique_ptr<impl::DB>(new impl::DB); +} catch (const std::bad_alloc &) { + throw "Memory allocation failed"; // TODO } -bool remove_db(Error *error, const StringCRef &, const DBOptions &) { - // TODO: Named DB is not supported yet. - GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet"); - return false; +void remove_db(const String &, const DBOptions &) { + throw "Not supported yet"; // TODO } } // namespace grnxx Modified: lib/grnxx/impl/Makefile.am (+1 -0) =================================================================== --- lib/grnxx/impl/Makefile.am 2014-10-31 21:43:45 +0900 (cc4ca15) +++ lib/grnxx/impl/Makefile.am 2014-11-05 17:35:04 +0900 (cec31bb) @@ -15,5 +15,6 @@ libgrnxx_impl_la_SOURCES = \ libgrnxx_impl_includedir = ${includedir}/grnxx/impl libgrnxx_impl_include_HEADERS = \ column.hpp \ + cursor.hpp \ db.hpp \ table.hpp Modified: lib/grnxx/impl/column.hpp (+11 -10) =================================================================== --- lib/grnxx/impl/column.hpp 2014-10-31 21:43:45 +0900 (8ea542d) +++ lib/grnxx/impl/column.hpp 2014-11-05 17:35:04 +0900 (98e4360) @@ -1,15 +1,16 @@ #ifndef GRNXX_IMPL_COLUMN_HPP #define GRNXX_IMPL_COLUMN_HPP -#include "grnxx/impl/column/column_bool.hpp" -#include "grnxx/impl/column/column_int.hpp" -#include "grnxx/impl/column/column_float.hpp" -#include "grnxx/impl/column/column_geo_point.hpp" -#include "grnxx/impl/column/column_text.hpp" -#include "grnxx/impl/column/column_vector_bool.hpp" -#include "grnxx/impl/column/column_vector_int.hpp" -#include "grnxx/impl/column/column_vector_float.hpp" -#include "grnxx/impl/column/column_vector_geo_point.hpp" -#include "grnxx/impl/column/column_vector_text.hpp" +#include "grnxx/impl/column/base.hpp" +//#include "grnxx/impl/column/scalar/bool.hpp" +//#include "grnxx/impl/column/scalar/int.hpp" +//#include "grnxx/impl/column/scalar/float.hpp" +//#include "grnxx/impl/column/scalar/geo_point.hpp" +//#include "grnxx/impl/column/scalar/text.hpp" +//#include "grnxx/impl/column/vector/bool.hpp" +//#include "grnxx/impl/column/vector/int.hpp" +//#include "grnxx/impl/column/vector/float.hpp" +//#include "grnxx/impl/column/vector/geo_point.hpp" +//#include "grnxx/impl/column/vector/text.hpp" #endif // GRNXX_IMPL_COLUMN_HPP Modified: lib/grnxx/impl/column/Makefile.am (+10 -29) =================================================================== --- lib/grnxx/impl/column/Makefile.am 2014-10-31 21:43:45 +0900 (fb38d8f) +++ lib/grnxx/impl/column/Makefile.am 2014-11-05 17:35:04 +0900 (db32fcd) @@ -1,39 +1,20 @@ -#SUBDIRS = \ -# sub +SUBDIRS = \ + scalar \ + vector lib_LTLIBRARIES = libgrnxx_impl_column.la -#libgrnxx_impl_column_la_LIBADD = \ -# sub/libgrnxx_impl_column_sub.la +libgrnxx_impl_column_la_LIBADD = \ + scalar/libgrnxx_impl_column_scalar.la \ + vector/libgrnxx_impl_column_vector.la libgrnxx_impl_column_la_LDFLAGS = @AM_LTLDFLAGS@ libgrnxx_impl_column_la_SOURCES = \ - column.cpp \ - column_base.cpp \ - column_float.cpp \ - column_int.cpp \ - column_text.cpp \ - column_vector_int.cpp \ - column_vector_float.cpp \ - column_vector_geo_point.cpp \ - column_vector_text.cpp - -# column_bool.cpp \ -# column_float.cpp \ -# column_geo_point.cpp \ -# column_vector_bool.cpp + base.cpp libgrnxx_impl_column_includedir = ${includedir}/grnxx/impl/column libgrnxx_impl_column_include_HEADERS = \ - column.hpp \ - column_base.hpp \ - column_bool.hpp \ - column_float.hpp \ - column_geo_point.hpp \ - column_int.hpp \ - column_vector_bool.hpp \ - column_vector_float.hpp \ - column_vector_geo_point.hpp \ - column_vector_int.hpp \ - column_vector_text.hpp + base.hpp \ + scalar.hpp \ + vector.hpp Added: lib/grnxx/impl/column/base.cpp (+254 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/base.cpp 2014-11-05 17:35:04 +0900 (42c8403) @@ -0,0 +1,254 @@ +#include "grnxx/impl/column/base.hpp" + +//#include "grnxx/impl/column/scalar.hpp" +//#include "grnxx/impl/column/vector.hpp" +#include "grnxx/impl/db.hpp" +#include "grnxx/impl/table.hpp" +//#include "grnxx/index.hpp" + +namespace grnxx { +namespace impl { + +ColumnBase::ColumnBase(Table *table, + const String &name, + DataType data_type, + Table *reference_table) + : ColumnInterface(), + table_(table), + name_(name), + data_type_(data_type), + reference_table_(reference_table), + has_key_attribute_(false) {} + +ColumnBase::~ColumnBase() {} + +TableInterface *ColumnBase::table() const { + return table_; +} + +TableInterface *ColumnBase::reference_table() const { + return reference_table_; +} + +//Index *ColumnBase::create_index(Error *error, +// const StringCRef &name, +// IndexType type, +// const IndexOptions &options) { +// if (find_index(nullptr, name)) { +// GRNXX_ERROR_SET(error, ALREADY_EXISTS, +// "Index already exists: name = \"%.*s\"", +// static_cast<int>(name.size()), name.data()); +// return nullptr; +// } +// if (!indexes_.reserve(error, indexes_.size() + 1)) { +// return nullptr; +// } +// unique_ptr<Index> new_index = +// Index::create(error, this, name, type, options); +// if (!new_index) { +// return nullptr; +// } +// indexes_.push_back(error, std::move(new_index)); +// return indexes_.back().get(); +//} + +//bool ColumnBase::remove_index(Error *error, const StringCRef &name) { +// Int index_id; +// if (!find_index_with_id(error, name, &index_id)) { +// return false; +// } +// if (!indexes_[index_id]->is_removable()) { +// GRNXX_ERROR_SET(error, NOT_REMOVABLE, +// "Index is not removable: name = \"%.*s\"", +// static_cast<int>(name.size()), name.data()); +// return false; +// } +// indexes_.erase(index_id); +// return true; +//} + +//bool ColumnBase::rename_index(Error *error, +// const StringCRef &name, +// const StringCRef &new_name) { +// Int index_id; +// if (!find_index_with_id(error, name, &index_id)) { +// return false; +// } +// if (name == new_name) { +// return true; +// } +// if (find_index(nullptr, new_name)) { +// GRNXX_ERROR_SET(error, ALREADY_EXISTS, +// "Index already exists: new_name = \"%.*s\"", +// static_cast<int>(new_name.size()), new_name.data()); +// return false; +// } +// return indexes_[index_id]->rename(error, new_name); +//} + +//bool ColumnBase::reorder_index(Error *error, +// const StringCRef &name, +// const StringCRef &prev_name) { +// Int index_id; +// if (!find_index_with_id(error, name, &index_id)) { +// return false; +// } +// Int new_index_id = 0; +// if (prev_name.size() != 0) { +// Int prev_index_id; +// if (!find_index_with_id(error, prev_name, &prev_index_id)) { +// return false; +// } +// if (index_id <= prev_index_id) { +// new_index_id = prev_index_id; +// } else { +// new_index_id = prev_index_id + 1; +// } +// } +// for ( ; index_id < new_index_id; ++index_id) { +// std::swap(indexes_[index_id], indexes_[index_id + 1]); +// } +// for ( ; index_id > new_index_id; --index_id) { +// std::swap(indexes_[index_id], indexes_[index_id - 1]); +// } +// return true; +//} + +//Index *ColumnBase::find_index(Error *error, const StringCRef &name) const { +// for (Int index_id = 0; index_id < num_indexes(); ++index_id) { +// if (name == indexes_[index_id]->name()) { +// return indexes_[index_id].get(); +// } +// } +// GRNXX_ERROR_SET(error, NOT_FOUND, "Index not found"); +// return nullptr; +//} + +//bool ColumnBase::set(Error *error, Int, const Datum &) { +// GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet"); +// return false; +//} + +//bool ColumnBase::get(Error *error, Int, Datum *) const { +// GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet"); +// return false; +//} + +//bool ColumnBase::contains(const Datum &datum) const { +// return find_one(datum) != NULL_ROW_ID; +//} + +Int ColumnBase::find_one(const Datum &) const { + // TODO: This function should be pure virtual. + return Int::na(); +} + +std::unique_ptr<ColumnBase> ColumnBase::create(Table *table, + const String &name, + DataType data_type, + const ColumnOptions &options) { + throw "Not supported yet"; // TODO +// switch (data_type) { +// case BOOL_DATA: { +// return impl::Column<Bool>::create(error, table, name, options); +// } +// case INT_DATA: { +// return impl::Column<Int>::create(error, table, name, options); +// } +// case FLOAT_DATA: { +// return impl::Column<Float>::create(error, table, name, options); +// } +// case GEO_POINT_DATA: { +// return impl::Column<GeoPoint>::create(error, table, name, options); +// } +// case TEXT_DATA: { +// return impl::Column<Text>::create(error, table, name, options); +// } +// case BOOL_VECTOR_DATA: { +// return impl::Column<Vector<Bool>>::create(error, table, name, options); +// } +// case INT_VECTOR_DATA: { +// return impl::Column<Vector<Int>>::create(error, table, name, options); +// } +// case FLOAT_VECTOR_DATA: { +// return impl::Column<Vector<Float>>::create(error, table, name, options); +// } +// case GEO_POINT_VECTOR_DATA: { +// return impl::Column<Vector<GeoPoint>>::create(error, table, name, options); +// } +// case TEXT_VECTOR_DATA: { +// return impl::Column<Vector<Text>>::create(error, table, name, options); +// } +// default: { +// // TODO: Other data types are not supported yet. +// GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet"); +// return nullptr; +// } +// } +} + +void ColumnBase::rename(const String &new_name) { + name_.assign(new_name); +} + +bool ColumnBase::is_removable() const { + // TODO: Reference column is not supported yet. + return true; +} + +void ColumnBase::set_key_attribute() { + throw "Not supported yet"; // TODO +} + +void ColumnBase::unset_key_attribute() { + throw "Not supported yet"; // TODO +} + +void ColumnBase::set_initial_key(Int, const Datum &) { + throw "Not supported yet"; // TODO +} + +void ColumnBase::clear_references(Int) { + throw "Not supported yet"; // TODO +} + +//bool ColumnBase::initialize_base(Error *error, +// Table *table, +// const StringCRef &name, +// DataType data_type, +// const ColumnOptions &options) { +// table_ = table; +// if (!name_.assign(error, name)) { +// return false; +// } +// data_type_ = data_type; +// if ((data_type == INT_DATA) || (data_type == INT_VECTOR_DATA)) { +// if (options.ref_table_name.size() != 0) { +// auto ref_table = table_->_db()->find_table(error, options.ref_table_name); +// if (!ref_table) { +// return false; +// } +// ref_table_ = ref_table; +// } +// } +// return true; +//} + +//Index *ColumnBase::find_index_with_id(Error *error, +// const StringCRef &name, +// Int *index_id) const { +// for (Int i = 0; i < num_indexes(); ++i) { +// if (name == indexes_[i]->name()) { +// if (index_id != nullptr) { +// *index_id = i; +// } +// return indexes_[i].get(); +// } +// } +// GRNXX_ERROR_SET(error, NOT_FOUND, "Index not found: name = \"%.*s\"", +// static_cast<int>(name.size()), name.data()); +// return nullptr; +//} + +} // namespace impl +} // namespace grnxx Added: lib/grnxx/impl/column/base.hpp (+150 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/base.hpp 2014-11-05 17:35:04 +0900 (c437ff4) @@ -0,0 +1,150 @@ +#ifndef GRNXX_IMPL_COLUMN_BASE_HPP +#define GRNXX_IMPL_COLUMN_BASE_HPP + +#include <memory> + +#include "grnxx/column.hpp" + +namespace grnxx { +namespace impl { + +using TableInterface = grnxx::Table; +using ColumnInterface = grnxx::Column; + +class Table; + +class Index; // TODO + +class ColumnBase : public ColumnInterface { + public: + // -- Public API (grnxx/column.hpp) -- + + ColumnBase(Table *table, + const String &name, + DataType data_type, + Table *reference_table = nullptr); + virtual ~ColumnBase(); + + TableInterface *table() const; + String name() const { + return name_; + } + DataType data_type() const { + return data_type_; + } + TableInterface *reference_table() const; + bool has_key_attribute() const { + return has_key_attribute_; + } + size_t num_indexes() const { + return indexes_.size(); + } + +// Index *create_index( +// Error *error, +// const String &name, +// IndexType type, +// const IndexOptions &options = IndexOptions()); +// bool remove_index(Error *error, const String &name); +// bool rename_index(Error *error, +// const String &name, +// const String &new_name); +// bool reorder_index(Error *error, +// const String &name, +// const String &prev_name); + +// Index *get_index(Int index_id) const { +// return indexes_[index_id].get(); +// } +// Index *find_index(Error *error, const String &name) const; + +// bool set(Error *error, Int row_id, const Datum &datum); +// bool get(Error *error, Int row_id, Datum *datum) const; + +// bool contains(const Datum &datum) const; + Int find_one(const Datum &datum) const; + + // -- Internal API -- + + // Create a new column. + // + // On success, returns the column. + // On failure, throws an exception. + static std::unique_ptr<ColumnBase> create( + Table *table, + const String &name, + DataType data_type, + const ColumnOptions &options = ColumnOptions()); + + // Return the owner table. + Table *_table() const { + return table_; + } + // Return the referenced (parent) table. + // If "this" is not a reference column, returns nullptr. + Table *_reference_table() const { + return reference_table_; + } + + // Change the column name. + // + // On failure, throws an exception. + void rename(const String &new_name); + + // Return whether the column is removable or not. + bool is_removable() const; + + // Set the key attribute. + // + // On failure, throws an exception. + virtual void set_key_attribute(); + // Unset the key attribute. + // + // On failure, throws an exception. + virtual void unset_key_attribute(); + + // Set the initial key. + // + // On failure, throws an exception. + virtual void set_initial_key(Int row_id, const Datum &key); + + // Unset the value. + virtual void unset(Int row_id) = 0; + + // Replace references to "row_id" with NULL. + virtual void clear_references(Int row_id); + + protected: + Table *table_; + String name_; + DataType data_type_; + Table *reference_table_; + bool has_key_attribute_; + Array<std::unique_ptr<Index>> indexes_; + +// // Initialize the base members. +// // +// // On success, returns true. +// // On failure, returns false and stores error information into "*error" if +// // "error" != nullptr. +// bool initialize_base(Error *error, +// Table *table, +// const String &name, +// DataType data_type, +// const ColumnOptions &options = ColumnOptions()); + +// private: +// // Find an index with its ID. +// // +// // On success, returns a pointer to the index. +// // On failure, returns nullptr and stores error information into "*error" if +// // "error" != nullptr. +// Index *find_index_with_id(Error *error, +// const String &name, +// Int *column_id) const; +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_BASE_HPP Modified: lib/grnxx/impl/column/column.hpp (+1 -1) =================================================================== --- lib/grnxx/impl/column/column.hpp 2014-10-31 21:43:45 +0900 (a440562) +++ lib/grnxx/impl/column/column.hpp 2014-11-05 17:35:04 +0900 (4989837) @@ -1,7 +1,7 @@ #ifndef GRNXX_IMPL_COLUMN_COLUMN_HPP #define GRNXX_IMPL_COLUMN_COLUMN_HPP -#include "grnxx/impl/column/column_base.hpp" +#include "grnxx/impl/column/base.hpp" namespace grnxx { namespace impl { Deleted: lib/grnxx/impl/column/column_base.cpp (+0 -263) 100644 =================================================================== --- lib/grnxx/impl/column/column_base.cpp 2014-10-31 21:43:45 +0900 (6f2817e) +++ /dev/null @@ -1,263 +0,0 @@ -#include "grnxx/impl/column/column_base.hpp" - -#include "grnxx/impl/column/column.hpp" -#include "grnxx/impl/column/column_bool.hpp" -#include "grnxx/impl/column/column_int.hpp" -#include "grnxx/impl/column/column_float.hpp" -#include "grnxx/impl/column/column_geo_point.hpp" -#include "grnxx/impl/column/column_text.hpp" -#include "grnxx/impl/column/column_vector_bool.hpp" -#include "grnxx/impl/column/column_vector_int.hpp" -#include "grnxx/impl/column/column_vector_float.hpp" -#include "grnxx/impl/column/column_vector_geo_point.hpp" -#include "grnxx/impl/column/column_vector_text.hpp" -#include "grnxx/impl/db.hpp" -#include "grnxx/impl/table.hpp" -#include "grnxx/index.hpp" - -namespace grnxx { -namespace impl { - -ColumnBase::ColumnBase() - : ColumnInterface(), - table_(nullptr), - name_(), - data_type_(), - ref_table_(nullptr), - has_key_attribute_(false) {} - -ColumnBase::~ColumnBase() {} - -TableInterface *ColumnBase::table() const { - return table_; -} - -TableInterface *ColumnBase::ref_table() const { - return ref_table_; -} - -Index *ColumnBase::create_index(Error *error, - const StringCRef &name, - IndexType type, - const IndexOptions &options) { - if (find_index(nullptr, name)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, - "Index already exists: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); - return nullptr; - } - if (!indexes_.reserve(error, indexes_.size() + 1)) { - return nullptr; - } - unique_ptr<Index> new_index = - Index::create(error, this, name, type, options); - if (!new_index) { - return nullptr; - } - indexes_.push_back(error, std::move(new_index)); - return indexes_.back().get(); -} - -bool ColumnBase::remove_index(Error *error, const StringCRef &name) { - Int index_id; - if (!find_index_with_id(error, name, &index_id)) { - return false; - } - if (!indexes_[index_id]->is_removable()) { - GRNXX_ERROR_SET(error, NOT_REMOVABLE, - "Index is not removable: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); - return false; - } - indexes_.erase(index_id); - return true; -} - -bool ColumnBase::rename_index(Error *error, - const StringCRef &name, - const StringCRef &new_name) { - Int index_id; - if (!find_index_with_id(error, name, &index_id)) { - return false; - } - if (name == new_name) { - return true; - } - if (find_index(nullptr, new_name)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, - "Index already exists: new_name = \"%.*s\"", - static_cast<int>(new_name.size()), new_name.data()); - return false; - } - return indexes_[index_id]->rename(error, new_name); -} - -bool ColumnBase::reorder_index(Error *error, - const StringCRef &name, - const StringCRef &prev_name) { - Int index_id; - if (!find_index_with_id(error, name, &index_id)) { - return false; - } - Int new_index_id = 0; - if (prev_name.size() != 0) { - Int prev_index_id; - if (!find_index_with_id(error, prev_name, &prev_index_id)) { - return false; - } - if (index_id <= prev_index_id) { - new_index_id = prev_index_id; - } else { - new_index_id = prev_index_id + 1; - } - } - for ( ; index_id < new_index_id; ++index_id) { - std::swap(indexes_[index_id], indexes_[index_id + 1]); - } - for ( ; index_id > new_index_id; --index_id) { - std::swap(indexes_[index_id], indexes_[index_id - 1]); - } - return true; -} - -Index *ColumnBase::find_index(Error *error, const StringCRef &name) const { - for (Int index_id = 0; index_id < num_indexes(); ++index_id) { - if (name == indexes_[index_id]->name()) { - return indexes_[index_id].get(); - } - } - GRNXX_ERROR_SET(error, NOT_FOUND, "Index not found"); - return nullptr; -} - -bool ColumnBase::set(Error *error, Int, const Datum &) { - GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet"); - return false; -} - -bool ColumnBase::get(Error *error, Int, Datum *) const { - GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet"); - return false; -} - -bool ColumnBase::contains(const Datum &datum) const { - return find_one(datum) != NULL_ROW_ID; -} - -Int ColumnBase::find_one(const Datum &) const { - // TODO: This function should be pure virtual. - return NULL_ROW_ID; -} - -unique_ptr<ColumnBase> ColumnBase::create(Error *error, - Table *table, - const StringCRef &name, - DataType data_type, - const ColumnOptions &options) { - switch (data_type) { - case BOOL_DATA: { - return impl::Column<Bool>::create(error, table, name, options); - } - case INT_DATA: { - return impl::Column<Int>::create(error, table, name, options); - } - case FLOAT_DATA: { - return impl::Column<Float>::create(error, table, name, options); - } - case GEO_POINT_DATA: { - return impl::Column<GeoPoint>::create(error, table, name, options); - } - case TEXT_DATA: { - return impl::Column<Text>::create(error, table, name, options); - } - case BOOL_VECTOR_DATA: { - return impl::Column<Vector<Bool>>::create(error, table, name, options); - } - case INT_VECTOR_DATA: { - return impl::Column<Vector<Int>>::create(error, table, name, options); - } - case FLOAT_VECTOR_DATA: { - return impl::Column<Vector<Float>>::create(error, table, name, options); - } - case GEO_POINT_VECTOR_DATA: { - return impl::Column<Vector<GeoPoint>>::create(error, table, name, options); - } - case TEXT_VECTOR_DATA: { - return impl::Column<Vector<Text>>::create(error, table, name, options); - } - default: { - // TODO: Other data types are not supported yet. - GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet"); - return nullptr; - } - } -} - -bool ColumnBase::rename(Error *error, const StringCRef &new_name) { - return name_.assign(error, new_name); -} - -bool ColumnBase::is_removable() { - // TODO: Reference column is not supported yet. - return true; -} - -bool ColumnBase::set_key_attribute(Error *error) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, "This type does not support Key"); - return false; -} - -bool ColumnBase::unset_key_attribute(Error *error) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, "This type does not support Key"); - return false; -} - -bool ColumnBase::set_initial_key(Error *error, Int, const Datum &) { - // TODO: Key column is not supported yet. - GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet"); - return false; -} - -void ColumnBase::clear_references(Int) { -} - -bool ColumnBase::initialize_base(Error *error, - Table *table, - const StringCRef &name, - DataType data_type, - const ColumnOptions &options) { - table_ = table; - if (!name_.assign(error, name)) { - return false; - } - data_type_ = data_type; - if ((data_type == INT_DATA) || (data_type == INT_VECTOR_DATA)) { - if (options.ref_table_name.size() != 0) { - auto ref_table = table_->_db()->find_table(error, options.ref_table_name); - if (!ref_table) { - return false; - } - ref_table_ = ref_table; - } - } - return true; -} - -Index *ColumnBase::find_index_with_id(Error *error, - const StringCRef &name, - Int *index_id) const { - for (Int i = 0; i < num_indexes(); ++i) { - if (name == indexes_[i]->name()) { - if (index_id != nullptr) { - *index_id = i; - } - return indexes_[i].get(); - } - } - GRNXX_ERROR_SET(error, NOT_FOUND, "Index not found: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); - return nullptr; -} - -} // namespace impl -} // namespace grnxx Deleted: lib/grnxx/impl/column/column_base.hpp (+0 -162) 100644 =================================================================== --- lib/grnxx/impl/column/column_base.hpp 2014-10-31 21:43:45 +0900 (ad32fdb) +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef GRNXX_IMPL_COLUMN_COLUMN_BASE_HPP -#define GRNXX_IMPL_COLUMN_COLUMN_BASE_HPP - -#include "grnxx/column.hpp" -#include "grnxx/name.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { -namespace impl { - -using TableInterface = grnxx::Table; -using ColumnInterface = grnxx::Column; - -class Table; - -class ColumnBase : public ColumnInterface { - public: - // -- Public API (grnxx/column.hpp) -- - - ColumnBase(); - virtual ~ColumnBase(); - - TableInterface *table() const; - StringCRef name() const { - return name_.ref(); - } - DataType data_type() const { - return data_type_; - } - TableInterface *ref_table() const; - bool has_key_attribute() const { - return has_key_attribute_; - } - Int num_indexes() const { - return indexes_.size(); - } - - Index *create_index( - Error *error, - const StringCRef &name, - IndexType type, - const IndexOptions &options = IndexOptions()); - bool remove_index(Error *error, const StringCRef &name); - bool rename_index(Error *error, - const StringCRef &name, - const StringCRef &new_name); - bool reorder_index(Error *error, - const StringCRef &name, - const StringCRef &prev_name); - - Index *get_index(Int index_id) const { - return indexes_[index_id].get(); - } - Index *find_index(Error *error, const StringCRef &name) const; - - bool set(Error *error, Int row_id, const Datum &datum); - bool get(Error *error, Int row_id, Datum *datum) const; - - bool contains(const Datum &datum) const; - Int find_one(const Datum &datum) const; - - // -- Internal API -- - - // Create a new column. - // - // On success, returns a pointer to the column. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<ColumnBase> create( - Error *error, - Table *table, - const StringCRef &name, - DataType data_type, - const ColumnOptions &options = ColumnOptions()); - - // Return the owner table. - Table *_table() const { - return table_; - } - // Return the referenced (parent) table, or nullptr if the column is not a - // reference column. - Table *_ref_table() const { - return ref_table_; - } - - // Change the column name. - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - bool rename(Error *error, const StringCRef &new_name); - - // Return whether the column is removable or not. - bool is_removable(); - - // Set the key attribute. - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool set_key_attribute(Error *error); - // Unset the key attribute. - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool unset_key_attribute(Error *error); - - // Set the initial key. - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool set_initial_key(Error *error, Int row_id, const Datum &key); - - // Set the default value. - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool set_default_value(Error *error, Int row_id) = 0; - - // Unset the value. - virtual void unset(Int row_id) = 0; - - // Replace references to "row_id" with NULL. - virtual void clear_references(Int row_id); - - protected: - Table *table_; - Name name_; - DataType data_type_; - Table *ref_table_; - bool has_key_attribute_; - Array<unique_ptr<Index>> indexes_; - - // Initialize the base members. - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - bool initialize_base(Error *error, - Table *table, - const StringCRef &name, - DataType data_type, - const ColumnOptions &options = ColumnOptions()); - - private: - // Find an index with its ID. - // - // On success, returns a pointer to the index. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - Index *find_index_with_id(Error *error, - const StringCRef &name, - Int *column_id) const; -}; - -} // namespace impl -} // namespace grnxx - -#endif // GRNXX_IMPL_COLUMN_COLUMN_BASE_HPP Added: lib/grnxx/impl/column/scalar.hpp (+10 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/scalar.hpp 2014-11-05 17:35:04 +0900 (f443aff) @@ -0,0 +1,10 @@ +#ifndef GRNXX_IMPL_COLUMN_SCALAR_HPP +#define GRNXX_IMPL_COLUMN_SCALAR_HPP + +#include "grnxx/impl/column/scalar/bool.hpp" +#include "grnxx/impl/column/scalar/float.hpp" +#include "grnxx/impl/column/scalar/geo_point.hpp" +#include "grnxx/impl/column/scalar/int.hpp" +#include "grnxx/impl/column/scalar/text.hpp" + +#endif // GRNXX_IMPL_COLUMN_SCALAR_HPP Added: lib/grnxx/impl/column/scalar/Makefile.am (+25 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/scalar/Makefile.am 2014-11-05 17:35:04 +0900 (f706517) @@ -0,0 +1,25 @@ +#SUBDIRS = \ +# sub + +lib_LTLIBRARIES = libgrnxx_impl_column_scalar.la + +#libgrnxx_impl_column_scalar_la_LIBADD = \ +# sub/libgrnxx_impl_column_scalar_sub.la + +libgrnxx_impl_column_scalar_la_LDFLAGS = @AM_LTLDFLAGS@ + +libgrnxx_impl_column_scalar_la_SOURCES = + +# bool.cpp \ +# float.cpp \ +# geo_point.cpp \ +# int.cpp \ +# text.cpp + +libgrnxx_impl_column_scalar_includedir = ${includedir}/grnxx/impl/column/scalar +libgrnxx_impl_column_scalar_include_HEADERS = \ + bool.hpp \ + float.hpp \ + geo_point.hpp \ + int.hpp \ + text.hpp Copied: lib/grnxx/impl/column/scalar/bool.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/scalar/bool.hpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/scalar/float.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/scalar/float.hpp (+0 -0) 100% =================================================================== Copied: lib/grnxx/impl/column/scalar/geo_point.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/scalar/geo_point.hpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/scalar/int.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/scalar/int.hpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/scalar/text.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/scalar/text.hpp (+0 -0) 100% =================================================================== Added: lib/grnxx/impl/column/vector.hpp (+10 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/vector.hpp 2014-11-05 17:35:04 +0900 (aed3214) @@ -0,0 +1,10 @@ +#ifndef GRNXX_IMPL_COLUMN_VECTOR_HPP +#define GRNXX_IMPL_COLUMN_VECTOR_HPP + +#include "grnxx/impl/column/vector/bool.hpp" +#include "grnxx/impl/column/vector/float.hpp" +#include "grnxx/impl/column/vector/geo_point.hpp" +#include "grnxx/impl/column/vector/int.hpp" +#include "grnxx/impl/column/vector/text.hpp" + +#endif // GRNXX_IMPL_COLUMN_VECTOR_HPP Added: lib/grnxx/impl/column/vector/Makefile.am (+25 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/vector/Makefile.am 2014-11-05 17:35:04 +0900 (4c68d73) @@ -0,0 +1,25 @@ +#SUBDIRS = \ +# sub + +lib_LTLIBRARIES = libgrnxx_impl_column_vector.la + +#libgrnxx_impl_column_vector_la_LIBADD = \ +# sub/libgrnxx_impl_column_vector_sub.la + +libgrnxx_impl_column_vector_la_LDFLAGS = @AM_LTLDFLAGS@ + +libgrnxx_impl_column_vector_la_SOURCES = + +# bool.cpp \ +# float.cpp \ +# geo_point.cpp \ +# int.cpp \ +# text.cpp + +libgrnxx_impl_column_vector_includedir = ${includedir}/grnxx/impl/column/vector +libgrnxx_impl_column_vector_include_HEADERS = \ + bool.hpp \ + float.hpp \ + geo_point.hpp \ + int.hpp \ + text.hpp Copied: lib/grnxx/impl/column/vector/bool.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/bool.hpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/float.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/float.hpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/geo_point.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/geo_point.hpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/int.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/int.hpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/text.cpp (+0 -0) 100% =================================================================== Renamed: lib/grnxx/impl/column/vector/text.hpp (+0 -0) 100% =================================================================== Added: lib/grnxx/impl/cursor.hpp (+24 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/cursor.hpp 2014-11-05 17:35:04 +0900 (432e1c4) @@ -0,0 +1,24 @@ +#ifndef GRNXX_IMPL_CURSOR_HPP +#define GRNXX_IMPL_CURSOR_HPP + +#include "grnxx/cursor.hpp" + +namespace grnxx { +namespace impl { + +class EmptyCursor : public Cursor { + public: + // -- Public API -- + + EmptyCursor() = default; + ~EmptyCursor() = default; + + size_t read(ArrayRef<Record>) { + return 0; + } +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_CURSOR_HPP Modified: lib/grnxx/impl/db.cpp (+36 -68) =================================================================== --- lib/grnxx/impl/db.cpp 2014-10-31 21:43:45 +0900 (2ccb816) +++ lib/grnxx/impl/db.cpp 2014-11-05 17:35:04 +0900 (c04e7e8) @@ -7,72 +7,51 @@ DB::DB() : DBInterface(), tables_() {} DB::~DB() {} -Table *DB::create_table(Error *error, - const StringCRef &name, - const TableOptions &options) { - if (find_table(nullptr, name)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, - "Table already exists: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); - return nullptr; +Table *DB::create_table(const String &name, const TableOptions &options) { + if (find_table(name)) { + throw "Table already exists"; // TODO } - if (!tables_.reserve(error, num_tables() + 1)) { - return nullptr; - } - unique_ptr<Table> new_table = Table::create(error, this, name, options); - if (!new_table) { - return nullptr; - } - tables_.push_back(error, std::move(new_table)); + tables_.reserve(num_tables() + 1); + std::unique_ptr<Table> new_table = Table::create(this, name, options); + tables_.push_back(std::move(new_table)); return tables_.back().get(); } -bool DB::remove_table(Error *error, const StringCRef &name) { - Int table_id; - if (!find_table_with_id(error, name, &table_id)) { - return false; +void DB::remove_table(const String &name) { + size_t table_id; + if (!find_table_with_id(name, &table_id)) { + throw "Table not found"; // TODO } if (!tables_[table_id]->is_removable()) { - GRNXX_ERROR_SET(error, NOT_REMOVABLE, - "Table is not removable: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); - return false; + throw "Table not removable"; // TODO } tables_.erase(table_id); - return true; } -bool DB::rename_table(Error *error, - const StringCRef &name, - const StringCRef &new_name) { - Int table_id; - if (!find_table_with_id(error, name, &table_id)) { - return false; +void DB::rename_table(const String &name, const String &new_name) { + size_t table_id; + if (!find_table_with_id(name, &table_id)) { + throw "Table not found"; // TODO } if (name == new_name) { - return true; + return; } - if (find_table(nullptr, new_name)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, - "Table already exists: new_name = \"%.*s\"", - static_cast<int>(new_name.size()), new_name.data()); - return false; + if (find_table(new_name)) { + throw "Table already exists"; // TODO } - return tables_[table_id]->rename(error, new_name); + tables_[table_id]->rename(new_name); } -bool DB::reorder_table(Error *error, - const StringCRef &name, - const StringCRef &prev_name) { - Int table_id; - if (!find_table_with_id(error, name, &table_id)) { - return false; +void DB::reorder_table(const String &name, const String &prev_name) { + size_t table_id; + if (!find_table_with_id(name, &table_id)) { + throw "Table not found"; // TODO } - Int new_table_id = 0; + size_t new_table_id = 0; if (prev_name.size() != 0) { - Int prev_table_id; - if (!find_table_with_id(error, prev_name, &prev_table_id)) { - return false; + size_t prev_table_id; + if (!find_table_with_id(prev_name, &prev_table_id)) { + throw "Table not found"; // TODO } if (table_id <= prev_table_id) { new_table_id = prev_table_id; @@ -86,41 +65,30 @@ bool DB::reorder_table(Error *error, for ( ; table_id > new_table_id; --table_id) { std::swap(tables_[table_id], tables_[table_id - 1]); } - return true; } -Table *DB::find_table(Error *error, const StringCRef &name) const { - for (Int table_id = 0; table_id < num_tables(); ++table_id) { - if (name == tables_[table_id]->name()) { - return tables_[table_id].get(); +Table *DB::find_table(const String &name) const { + for (size_t i = 0; i < num_tables(); ++i) { + if (name == tables_[i]->name()) { + return tables_[i].get(); } } - GRNXX_ERROR_SET(error, NOT_FOUND, "Table not found: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); return nullptr; } -bool DB::save(Error *error, - const StringCRef &, - const DBOptions &) const { - // TODO: Named DB is not supported yet. - GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet"); - return false; +void DB::save(const String &, const DBOptions &) const { + throw "Not supported yet"; // TODO } -Table *DB::find_table_with_id(Error *error, - const StringCRef &name, - Int *table_id) const { - for (Int i = 0; i < num_tables(); ++i) { +Table *DB::find_table_with_id(const String &name, size_t *table_id) const { + for (size_t i = 0; i < num_tables(); ++i) { if (name == tables_[i]->name()) { - if (table_id != nullptr) { + if (table_id) { *table_id = i; } return tables_[i].get(); } } - GRNXX_ERROR_SET(error, NOT_FOUND, "Table not found: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); return nullptr; } Modified: lib/grnxx/impl/db.hpp (+18 -25) =================================================================== --- lib/grnxx/impl/db.hpp 2014-10-31 21:43:45 +0900 (a3537cb) +++ lib/grnxx/impl/db.hpp 2014-11-05 17:35:04 +0900 (99edc78) @@ -1,8 +1,12 @@ #ifndef GRNXX_IMPL_DB_HPP #define GRNXX_IMPL_DB_HPP +#include <memory> + +#include "grnxx/array.hpp" #include "grnxx/db.hpp" #include "grnxx/impl/table.hpp" +#include "grnxx/string.hpp" namespace grnxx { namespace impl { @@ -16,41 +20,30 @@ class DB : public DBInterface { DB(); ~DB(); - Int num_tables() const { + size_t num_tables() const { return tables_.size(); } - Table *create_table(Error *error, - const StringCRef &name, - const TableOptions &options); - bool remove_table(Error *error, const StringCRef &name); - bool rename_table(Error *error, - const StringCRef &name, - const StringCRef &new_name); - bool reorder_table(Error *error, - const StringCRef &name, - const StringCRef &prev_name); - - Table *get_table(Int table_id) const { - return tables_[table_id].get(); + Table *create_table(const String &name, const TableOptions &options); + void remove_table(const String &name); + void rename_table(const String &name, const String &new_name); + void reorder_table(const String &name, const String &prev_name); + + Table *get_table(size_t i) const { + return tables_[i].get(); } - Table *find_table(Error *error, const StringCRef &name) const; + Table *find_table(const String &name) const; - bool save(Error *error, - const StringCRef &path, - const DBOptions &options = DBOptions()) const; + void save(const String &path, const DBOptions &options = DBOptions()) const; private: - Array<unique_ptr<Table>> tables_; + Array<std::unique_ptr<Table>> tables_; // Find a table with its ID. // - // On success, returns a pointer to the table. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - Table *find_table_with_id(Error *error, - const StringCRef &name, - Int *table_id) const; + // If found, returns the table and stores its ID into "*table_id". + // If not found, returns nullptr. + Table *find_table_with_id(const String &name, size_t *table_id) const; }; } // namespace impl Modified: lib/grnxx/impl/table.cpp (+313 -376) =================================================================== --- lib/grnxx/impl/table.cpp 2014-10-31 21:43:45 +0900 (01d9859) +++ lib/grnxx/impl/table.cpp 2014-11-05 17:35:04 +0900 (5678cdc) @@ -1,117 +1,50 @@ #include "grnxx/impl/table.hpp" -#include "grnxx/cursor.hpp" +#include "grnxx/impl/cursor.hpp" #include "grnxx/impl/db.hpp" -#include <iostream> // For debug. - namespace grnxx { namespace impl { -// -- TableCursor -- +// -- TableRegularCursor -- -class TableCursor : public Cursor { +class TableRegularCursor : public Cursor { public: // -- Public API -- - ~TableCursor() {} + ~TableRegularCursor() {} - CursorResult read(Error *error, ArrayRef<Record> records); + size_t read(ArrayRef<Record> records); // -- Internal API -- - // Create a cursor. - // - // Returns a pointer to the cursor on success. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<TableCursor> create(Error *error, - const Table *table, + static std::unique_ptr<Cursor> create(const Table *table, const CursorOptions &options); - // Read records in regular order. - CursorResult regular_read(Error *error, ArrayRef<Record> records); - - // Read records in reverse order. - CursorResult reverse_read(Error *error, ArrayRef<Record> records); - private: const Table *table_; - Int offset_left_; - Int limit_left_; - OrderType order_type_; - Int next_row_id_; + int64_t max_row_id_; + bool is_full_; + size_t offset_left_; + size_t limit_left_; + int64_t next_row_id_; - explicit TableCursor(const Table *table); + TableRegularCursor(const Table *table, const CursorOptions &options); }; -CursorResult TableCursor::read(Error *error, ArrayRef<Record> records) { +size_t TableRegularCursor::read(ArrayRef<Record> records) { if (records.size() <= 0) { - return { true, 0 }; - } - switch (order_type_) { - case REGULAR_ORDER: { - return regular_read(error, records); - } - case REVERSE_ORDER: { - return reverse_read(error, records); - } - default: { - GRNXX_ERROR_SET(error, BROKEN, "Broken cursor"); - return { false, 0 }; - } + return 0; } -} - -unique_ptr<TableCursor> TableCursor::create(Error *error, - const Table *table, - const CursorOptions &options) { - unique_ptr<TableCursor> cursor(new (nothrow) TableCursor(table)); - if (!cursor) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - cursor->offset_left_ = options.offset; - cursor->limit_left_ = options.limit; - switch (options.order_type) { - case REGULAR_ORDER: { - cursor->order_type_ = REGULAR_ORDER; - cursor->next_row_id_ = MIN_ROW_ID; - break; - } - case REVERSE_ORDER: { - cursor->order_type_ = REVERSE_ORDER; - cursor->next_row_id_ = table->max_row_id(); - break; - } - default: { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid order type"); - return nullptr; - } - } - return cursor; -} - -TableCursor::TableCursor(const Table *table) - : Cursor(table), - table_(table), - offset_left_(), - limit_left_(), - order_type_(), - next_row_id_() {} - -CursorResult TableCursor::regular_read(Error *, ArrayRef<Record> records) { - Int count = 0; - bool has_false_bit = - table_->num_rows() != (table_->max_row_id() - MIN_ROW_ID + 1); - if (!has_false_bit) { + size_t count = 0; + if (is_full_) { // There are no false bits in the bitmap and bit checks are not required. - Int num_remaining_records = table_->max_row_id() - next_row_id_ + 1; + size_t num_remaining_records = max_row_id_ - next_row_id_ + 1; if (offset_left_ > 0) { if (offset_left_ >= num_remaining_records) { next_row_id_ += num_remaining_records; offset_left_ -= num_remaining_records; - return { true, 0 }; + return 0; } num_remaining_records -= offset_left_; next_row_id_ += offset_left_; @@ -125,15 +58,15 @@ CursorResult TableCursor::regular_read(Error *, ArrayRef<Record> records) { if (count > limit_left_) { count = limit_left_; } - for (Int i = 0; i < count; ++i) { - records.set(i, Record(next_row_id_, 0.0)); + for (size_t i = 0; i < count; ++i) { + records.set(i, Record(Int(next_row_id_), Float(0.0))); ++next_row_id_; --limit_left_; } } else { // There exist false bits in the bitmap and bit checks are required. - while (next_row_id_ <= table_->max_row_id()) { - if (!table_->get_bit(next_row_id_)) { + while (next_row_id_ <= max_row_id_) { + if (!table_->_test_row(next_row_id_)) { ++next_row_id_; continue; } @@ -141,7 +74,7 @@ CursorResult TableCursor::regular_read(Error *, ArrayRef<Record> records) { --offset_left_; ++next_row_id_; } else { - records.set(count, Record(next_row_id_, 0.0)); + records.set(count, Record(Int(next_row_id_), Float(0.0))); --limit_left_; ++count; ++next_row_id_; @@ -151,21 +84,65 @@ CursorResult TableCursor::regular_read(Error *, ArrayRef<Record> records) { } } } - return { true, count }; + return count; } -CursorResult TableCursor::reverse_read(Error *, ArrayRef<Record> records) { - Int count = 0; - bool has_false_bit = - table_->num_rows() != (table_->max_row_id() - MIN_ROW_ID + 1); - if (!has_false_bit) { +std::unique_ptr<Cursor> TableRegularCursor::create( + const Table *table, + const CursorOptions &options) { + if (table->is_empty()) { + return std::unique_ptr<Cursor>(new EmptyCursor); + } + return std::unique_ptr<Cursor>(new TableRegularCursor(table, options)); +} + +TableRegularCursor::TableRegularCursor(const Table *table, + const CursorOptions &options) + : table_(table), + max_row_id_(table->max_row_id().value()), + is_full_(table->is_full()), + offset_left_(options.offset), + limit_left_(options.limit), + next_row_id_(0) {} + +// -- TableReverseCursor -- + +class TableReverseCursor : public Cursor { + public: + // -- Public API -- + + ~TableReverseCursor() {} + + size_t read(ArrayRef<Record> records); + + // -- Internal API -- + + static std::unique_ptr<Cursor> create(const Table *table, + const CursorOptions &options); + + private: + const Table *table_; + bool is_full_; + size_t offset_left_; + size_t limit_left_; + int64_t next_row_id_; + + TableReverseCursor(const Table *table, const CursorOptions &options); +}; + +size_t TableReverseCursor::read(ArrayRef<Record> records) { + if (records.size() <= 0) { + return 0; + } + size_t count = 0; + if (is_full_) { // There are no false bits in the bitmap and bit checks are not required. - Int num_remaining_records = next_row_id_ - MIN_ROW_ID + 1; + size_t num_remaining_records = next_row_id_ + 1; if (offset_left_ > 0) { if (offset_left_ >= num_remaining_records) { next_row_id_ -= num_remaining_records; offset_left_ -= num_remaining_records; - return { true, 0 }; + return 0; } num_remaining_records -= offset_left_; next_row_id_ -= offset_left_; @@ -179,15 +156,15 @@ CursorResult TableCursor::reverse_read(Error *, ArrayRef<Record> records) { if (count > limit_left_) { count = limit_left_; } - for (Int i = 0; i < count; ++i) { - records.set(i, Record(next_row_id_, 0.0)); + for (size_t i = 0; i < count; ++i) { + records.set(i, Record(Int(next_row_id_), Float(0.0))); --next_row_id_; --limit_left_; } } else { - while (next_row_id_ >= MIN_ROW_ID) { + while (next_row_id_ >= 0) { // There exist false bits in the bitmap and bit checks are required. - if (!table_->get_bit(next_row_id_)) { + if (!table_->_test_row(next_row_id_)) { --next_row_id_; continue; } @@ -195,7 +172,7 @@ CursorResult TableCursor::reverse_read(Error *, ArrayRef<Record> records) { --offset_left_; --next_row_id_; } else { - records.set(count, Record(next_row_id_, 0.0)); + records.set(count, Record(Int(next_row_id_), Float(0.0))); --limit_left_; ++count; --next_row_id_; @@ -205,20 +182,37 @@ CursorResult TableCursor::reverse_read(Error *, ArrayRef<Record> records) { } } } - return { true, count }; + return count; } +std::unique_ptr<Cursor> TableReverseCursor::create( + const Table *table, + const CursorOptions &options) { + if (table->is_empty()) { + return std::unique_ptr<Cursor>(new EmptyCursor); + } + return std::unique_ptr<Cursor>(new TableReverseCursor(table, options)); +} + +TableReverseCursor::TableReverseCursor(const Table *table, + const CursorOptions &options) + : table_(table), + is_full_(table->is_full()), + offset_left_(options.offset), + limit_left_(options.limit), + next_row_id_(table->max_row_id().value()) {} + // -- Table -- -Table::Table() +Table::Table(DB *db, const String &name) : TableInterface(), - db_(nullptr), - name_(), + db_(db), + name_(name), columns_(), referrer_columns_(), key_column_(nullptr), num_rows_(0), - max_row_id_(MIN_ROW_ID - 1), + max_row_id_(NA()), bitmap_(), bitmap_indexes_() {} @@ -228,81 +222,61 @@ DBInterface *Table::db() const { return db_; } -ColumnBase *Table::create_column(Error *error, - const StringCRef &name, +ColumnBase *Table::create_column(const String &name, DataType data_type, const ColumnOptions &options) { - if (find_column(nullptr, name)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, - "Column already exists: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); - return nullptr; - } - if (!columns_.reserve(error, columns_.size() + 1)) { - return nullptr; - } - unique_ptr<ColumnBase> new_column = - ColumnBase::create(error, this, name, data_type, options); - if (!new_column) { - return nullptr; + if (find_column(name)) { + throw "Column already exists"; // TODO } - columns_.push_back(nullptr, std::move(new_column)); + columns_.reserve(columns_.size() + 1); + std::unique_ptr<ColumnBase> new_column = + ColumnBase::create(this, name, data_type, options); + columns_.push_back(std::move(new_column)); return columns_.back().get(); } -bool Table::remove_column(Error *error, const StringCRef &name) { - Int column_id; - if (!find_column_with_id(error, name, &column_id)) { - return false; +void Table::remove_column(const String &name) { + size_t column_id; + if (!find_column_with_id(name, &column_id)) { + throw "Column not found"; // TODO } if (!columns_[column_id]->is_removable()) { - GRNXX_ERROR_SET(error, NOT_REMOVABLE, - "Column is not removable: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); - return false; + throw "Column not removable"; // TODO } ColumnBase *column = columns_[column_id].get(); if (column == key_column_) { key_column_ = nullptr; } - if (column->ref_table()) { - column->_ref_table()->remove_referrer_column(nullptr, column); + if (column->reference_table()) { + column->_reference_table()->remove_referrer_column(column); } columns_.erase(column_id); - return true; } -bool Table::rename_column(Error *error, - const StringCRef &name, - const StringCRef &new_name) { - Int column_id; - if (!find_column_with_id(error, name, &column_id)) { - return false; +void Table::rename_column(const String &name, const String &new_name) { + size_t column_id; + if (!find_column_with_id(name, &column_id)) { + throw "Column not found"; // TODO } if (name == new_name) { - return true; + return; } - if (find_column(nullptr, new_name)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, - "Column already exists: new_name = \"%.*s\"", - static_cast<int>(new_name.size()), new_name.data()); - return false; + if (find_column(new_name)) { + throw "Column already exists"; // TODO } - return columns_[column_id]->rename(error, new_name); + columns_[column_id]->rename(new_name); } -bool Table::reorder_column(Error *error, - const StringCRef &name, - const StringCRef &prev_name) { - Int column_id; - if (!find_column_with_id(error, name, &column_id)) { - return false; +void Table::reorder_column(const String &name, const String &prev_name) { + size_t column_id; + if (!find_column_with_id(name, &column_id)) { + throw "Column not found"; // TODO } - Int new_column_id = 0; + size_t new_column_id = 0; if (prev_name.size() != 0) { - Int prev_column_id; - if (!find_column_with_id(error, prev_name, &prev_column_id)) { - return false; + size_t prev_column_id; + if (!find_column_with_id(prev_name, &prev_column_id)) { + throw "Column not found"; // TODO } if (column_id <= prev_column_id) { new_column_id = prev_column_id; @@ -316,209 +290,156 @@ bool Table::reorder_column(Error *error, for ( ; column_id > new_column_id; --column_id) { std::swap(columns_[column_id], columns_[column_id - 1]); } - return true; } -ColumnBase *Table::find_column(Error *error, const StringCRef &name) const { - for (Int column_id = 0; column_id < num_columns(); ++column_id) { - if (name == columns_[column_id]->name()) { - return columns_[column_id].get(); +ColumnBase *Table::find_column(const String &name) const { + for (size_t i = 0; i < num_columns(); ++i) { + if (name == columns_[i]->name()) { + return columns_[i].get(); } } - GRNXX_ERROR_SET(error, NOT_FOUND, "Column not found: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); return nullptr; } -bool Table::set_key_column(Error *error, const StringCRef &name) { +void Table::set_key_column(const String &name) { if (key_column_) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key column already exists"); - return false; + throw "Key column already exists"; // TODO } - ColumnBase *column = find_column(error, name); + ColumnBase *column = find_column(name); if (!column) { - return false; - } - if (!column->set_key_attribute(error)) { - return false; + throw "Column not found"; // TODO } + column->set_key_attribute(); key_column_ = column; - return true; } -bool Table::unset_key_column(Error *error) { +void Table::unset_key_column() { if (!key_column_) { - GRNXX_ERROR_SET(error, NOT_FOUND, "Key column not found"); - return false; - } - if (!key_column_->unset_key_attribute(error)) { - return false; + throw "Key column not found"; // TODO } + key_column_->unset_key_attribute(); key_column_ = nullptr; - return true; } -bool Table::insert_row(Error *error, - Int request_row_id, - const Datum &key, - Int *result_row_id) { - *result_row_id = NULL_ROW_ID; - Int next_row_id; - if (request_row_id == NULL_ROW_ID) { - next_row_id = find_zero_bit(); - } else if ((request_row_id < MIN_ROW_ID) || (request_row_id > MAX_ROW_ID)) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, - "Invalid argument: request_row_id = %" PRIi64, - request_row_id); - return false; - } else if (request_row_id > max_row_id()) { - next_row_id = request_row_id; - } else { - // Fails if the request row ID is used. - if (get_bit(request_row_id)) { - *result_row_id = request_row_id; - GRNXX_ERROR_SET(error, ALREADY_EXISTS, - "Row already exists: request_row_id = %" PRIi64, - request_row_id); - return false; +Int Table::insert_row(const Datum &key) { + if (key_column_) { + if (!find_row(key).is_na()) { + throw "Key already exists"; // TODO } - next_row_id = request_row_id; + } else if (key.type() != NA_DATA) { + throw "Wrong key"; // TODO + } + Int row_id = find_next_row_id(); + reserve_row(row_id); + if (key_column_) { + key_column_->set_initial_key(row_id, key); } + validate_row(row_id); + return row_id; +} - if (key_column()) { - // Fails if the key already exists. - *result_row_id = find_row(nullptr, key); - if (*result_row_id != NULL_ROW_ID) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key already exists"); - return false; +Int Table::find_or_insert_row(const Datum &key, bool *inserted) { + if (key_column_) { + Int row_id = find_row(key); + if (!row_id.is_na()) { + if (inserted) { + *inserted = false; + } + return row_id; } + } else if (key.type() != NA_DATA) { + throw "Wrong key"; // TODO } - - if (!reserve_bit(error, next_row_id)) { - return false; + Int row_id = find_next_row_id(); + reserve_row(row_id); + if (key_column_) { + key_column_->set_initial_key(row_id, key); } + validate_row(row_id); + *inserted = true; + return row_id; +} - if (key_column()) { - if (!key_column_->set_initial_key(error, next_row_id, key)) { - return false; - } +void Table::insert_row_at(Int row_id, const Datum &key) { + if (test_row(row_id)) { + throw "Row ID already validated"; // TODO } - - if (next_row_id > max_row_id()) { - // Fill non-key column values with the default values. - for (Int column_id = 0; column_id < num_columns(); ++column_id) { - if (columns_[column_id].get() != key_column()) { - if (!columns_[column_id]->set_default_value(error, next_row_id)) { - // Rollback the insertion. - if (key_column()) { - key_column_->unset(next_row_id); - } - for (Int i = 0; i < column_id; ++i) { - if (columns_[i].get() != key_column()) { - columns_[i]->unset(next_row_id); - } - } - return false; - } - } + if (row_id.value() < 0) { + throw "Negative row ID"; // TODO + } + if (key_column_) { + if (!find_row(key).is_na()) { + throw "Key already exists"; // TODO } - max_row_id_ = next_row_id; } - - set_bit(next_row_id); - ++num_rows_; - *result_row_id = next_row_id; - return true; + reserve_row(row_id); + if (key_column_) { + key_column_->set_initial_key(row_id, key); + } + validate_row(row_id); } -bool Table::remove_row(Error *error, Int row_id) { - if (!test_row(error, row_id)) { - return false; +void Table::remove_row(Int row_id) { + if (!test_row(row_id)) { + throw "Invalid row ID"; // TODO } // TODO: Check removability. - for (Int i = 0; i < referrer_columns_.size(); ++i) { + for (size_t i = 0; i < referrer_columns_.size(); ++i) { if (referrer_columns_[i]->has_key_attribute()) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This table is referred to from a key column"); - return false; + throw "Reffered to from a key column"; // TODO } } // Unset column values. - for (Int column_id = 0; column_id < num_columns(); ++column_id) { - columns_[column_id]->unset(row_id); - } - unset_bit(row_id); - --num_rows_; - if (num_rows_ == 0) { - max_row_id_ = MIN_ROW_ID - 1; - } else if (row_id == max_row_id()) { - Int block_id = (max_row_id() - 1) / 64; - while (block_id >= 0) { - if (bitmap_[block_id] != 0) { - break; - } - --block_id; - } - max_row_id_ = (block_id * 64) + 63 - ::__builtin_clzll(bitmap_[block_id]); + for (size_t i = 0; i < num_columns(); ++i) { + columns_[i]->unset(row_id); } + invalidate_row(row_id); // Clear referrers. - for (Int i = 0; i < referrer_columns_.size(); ++i) { + for (size_t i = 0; i < referrer_columns_.size(); ++i) { referrer_columns_[i]->clear_references(row_id); } - return true; } -bool Table::test_row(Error *error, Int row_id) const { - if ((row_id < MIN_ROW_ID) || (row_id > max_row_id())) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid row ID"); - return false; - } - if (!get_bit(row_id)) { - GRNXX_ERROR_SET(error, NOT_FOUND, "Removed row"); - return false; - } - return true; -} - -Int Table::find_row(Error *error, const Datum &key) const { +Int Table::find_row(const Datum &key) const { if (!key_column_) { - GRNXX_ERROR_SET(error, NO_KEY_COLUMN, "No key column"); - return NULL_ROW_ID; + throw "No key column"; // TODO } return key_column_->find_one(key); } -unique_ptr<Cursor> Table::create_cursor( - Error *error, +std::unique_ptr<Cursor> Table::create_cursor( const CursorOptions &options) const { - return TableCursor::create(error, this, options); + switch (options.order_type) { + case CURSOR_REGULAR_ORDER: { + return TableRegularCursor::create(this, options); + } + case CURSOR_REVERSE_ORDER: { + return TableReverseCursor::create(this, options); + } + default: { + throw "Invalid order type"; // TODO + } + } } -unique_ptr<Table> Table::create(Error *error, - DB *db, - const StringCRef &name, - const TableOptions &) { - unique_ptr<Table> table(new Table); - table->db_ = db; - if (!table->name_.assign(error, name)) { - return nullptr; - } - // Initialize the bitmap. - if (!table->reserve_bit(error, 0)) { - return nullptr; - } - table->set_bit(0); - // TODO: Apply options. +std::unique_ptr<Table> Table::create(DB *db, + const String &name, + const TableOptions &) try { + std::unique_ptr<Table> table(new Table(db, name)); return table; +} catch (const std::bad_alloc &) { + throw "Memory allocation failed"; // TODO } -bool Table::rename(Error *error, const StringCRef &new_name) { - return name_.assign(error, new_name); +void Table::rename(const String &new_name) { + if (name_ != new_name) { + name_.assign(new_name); + } } -bool Table::is_removable() { - // Referenced table (except self-reference) is not removable. - for (Int i = 0; i < referrer_columns_.size(); ++i) { +bool Table::is_removable() const { + // A referenced table (except self-reference) is not removable. + for (size_t i = 0; i < referrer_columns_.size(); ++i) { if (referrer_columns_[i]->table() != this) { return false; } @@ -526,107 +447,125 @@ bool Table::is_removable() { return true; } -bool Table::append_referrer_column(Error *error, ColumnBase *column) { - if (column->ref_table() != this) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong column"); - return false; +void Table::append_referrer_column(ColumnBase *column) { + if (column->reference_table() != this) { + throw "Wrong referrer column"; // TODO } - return referrer_columns_.push_back(error, column); + referrer_columns_.push_back(column); } -bool Table::remove_referrer_column(Error *error, ColumnBase *column) { - for (Int i = 0; i < referrer_columns_.size(); ++i) { +void Table::remove_referrer_column(ColumnBase *column) { + for (size_t i = 0; i < referrer_columns_.size(); ++i) { if (column == referrer_columns_[i]) { referrer_columns_.erase(i); - return true; + return; } } - GRNXX_ERROR_SET(error, NOT_FOUND, "Column not found"); - return false; + throw "Referrer column not found"; // TODO } -void Table::set_bit(Int i) { - bitmap_[i / 64] |= UInt(1) << (i % 64); - if (bitmap_[i / 64] == ~UInt(0)) { - for (Int index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) { - i /= 64; - bitmap_indexes_[index_id][i / 64] |= UInt(1) << (i % 64); - if (bitmap_indexes_[index_id][i / 64] != ~UInt(0)) { - break; - } - } +Int Table::find_next_row_id() const { + if (is_empty()) { + return Int(0); + } else if (is_full()) { + return Int(max_row_id_.value() + 1); } -} - -void Table::unset_bit(Int i) { - bool is_full = bitmap_[i / 64] == ~UInt(0); - bitmap_[i / 64] &= ~(UInt(1) << (i % 64)); - if (is_full) { - for (Int index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) { - i /= 64; - is_full = bitmap_indexes_[index_id][i / 64] == ~UInt(0); - bitmap_indexes_[index_id][i / 64] &= ~(UInt(1) << (i % 64)); - if (!is_full) { - break; - } - } - } -} - -Int Table::find_zero_bit() const { - if (num_rows() == (max_row_id() - MIN_ROW_ID + 1)) { - return max_row_id() + 1; - } - Int pos = 0; - for (Int i = bitmap_indexes_.size(); i > 0; ) { + size_t pos = 0; + for (size_t i = bitmap_indexes_.size(); i > 0; ) { + // TODO: ::__builtin_ctzll() is not available on VC++. pos = (pos * 64) + ::__builtin_ctzll(~bitmap_indexes_[--i][pos]); } - return (pos * 64) + ::__builtin_ctzll(~bitmap_[pos]); + // TODO: ::__builtin_ctzll() is not available on VC++. + return Int((pos * 64) + ::__builtin_ctzll(~bitmap_[pos])); } -bool Table::reserve_bit(Error *error, Int i) { - if (i > MAX_ROW_ID) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, - "Invalid argument: i = %" PRIi64, i); - return false; - } +void Table::reserve_row(Int row_id) { + // TODO: Define the upper limit for row ID. +// if (row_id.value() > MAX_ROW_ID_VALUE) { +// throw "Too large row ID"; // TODO +// } // Resize the bitmap if required. - Int block_id = i / 64; + size_t block_id = static_cast<size_t>(row_id.value()) / 64; if (block_id >= bitmap_.size()) { - if (!bitmap_.resize(error, block_id + 1, 0)) { - return false; - } + bitmap_.resize(block_id + 1, 0); } // Resize the existing bitmap indexes if required. - for (Int index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) { + for (size_t index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) { block_id /= 64; if (block_id >= bitmap_indexes_[index_id].size()) { - if (!bitmap_indexes_[index_id].resize(error, block_id + 1, 0)) { - return false; - } + bitmap_indexes_[index_id].resize(block_id + 1, 0); } } - // Add bitmap indexes if requires. - Int depth = bitmap_indexes_.size(); + // Add bitmap indexes if required. + size_t depth = bitmap_indexes_.size(); while (block_id > 0) { block_id /= 64; - if (!bitmap_indexes_.resize(error, depth + 1) || - !bitmap_indexes_[depth].resize(error, block_id + 1, 0)) { - return false; - } + bitmap_indexes_.resize(depth + 1); + bitmap_indexes_[depth].resize(block_id + 1, 0); if (depth == 0) { bitmap_indexes_[depth][0] = bitmap_[0] != 0; } else { bitmap_indexes_[depth][0] = bitmap_indexes_[depth - 1][0] != 0; } } - return true; } -ColumnBase *Table::find_column_with_id(Error *error, - const StringCRef &name, - Int *column_id) const { - for (Int i = 0; i < num_columns(); ++i) { +void Table::validate_row(Int row_id) { + // Update the bitmap and its indexes. + size_t bit_id = static_cast<size_t>(row_id.value()); + bitmap_[bit_id / 64] |= uint64_t(1) << (bit_id % 64); + if (bitmap_[bit_id / 64] == ~uint64_t(0)) { + for (size_t index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) { + bit_id /= 64; + bitmap_indexes_[index_id][bit_id / 64] |= uint64_t(1) << (bit_id % 64); + if (bitmap_indexes_[index_id][bit_id / 64] != ~uint64_t(0)) { + break; + } + } + } + // This works well even if "max_row_id_" is N/A. + if (row_id.value() > max_row_id_.value()) { + max_row_id_ = row_id; + } + ++num_rows_; +} + +void Table::invalidate_row(Int row_id) { + // Update the bitmap and its indexes. + size_t bit_id = static_cast<size_t>(row_id.value()); + bool is_full = (bitmap_[bit_id / 64] == ~uint64_t(0)); + bitmap_[bit_id / 64] &= ~(uint64_t(1) << (bit_id % 64)); + if (is_full) { + for (size_t index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) { + bit_id /= 64; + is_full = bitmap_indexes_[index_id][bit_id / 64] == ~uint64_t(0); + bitmap_indexes_[index_id][bit_id / 64] &= + ~(uint64_t(1) << (bit_id % 64)); + if (!is_full) { + break; + } + } + } + --num_rows_; + if (is_empty()) { + max_row_id_ = Int::na(); + } else if (row_id.value() == max_row_id_.value()) { + int64_t block_id = (row_id.value() - 1) / 64; + while (block_id >= 0) { + if (bitmap_[block_id] != 0) { + break; + } + --block_id; + } + // TODO: ::__builtin_clzll() is not available on VC++. + max_row_id_ = Int((block_id * 64) + 63 - + ::__builtin_clzll(bitmap_[block_id])); + } +} + +ColumnBase *Table::find_column_with_id(const String &name, + size_t *column_id) const { + for (size_t i = 0; i < num_columns(); ++i) { if (name == columns_[i]->name()) { if (column_id != nullptr) { *column_id = i; @@ -634,8 +573,6 @@ ColumnBase *Table::find_column_with_id(Error *error, return columns_[i].get(); } } - GRNXX_ERROR_SET(error, NOT_FOUND, "Column not found: name = \"%.*s\"", - static_cast<int>(name.size()), name.data()); return nullptr; } Modified: lib/grnxx/impl/table.hpp (+77 -78) =================================================================== --- lib/grnxx/impl/table.hpp 2014-10-31 21:43:45 +0900 (59863ee) +++ lib/grnxx/impl/table.hpp 2014-11-05 17:35:04 +0900 (9a62a99) @@ -1,7 +1,9 @@ #ifndef GRNXX_IMPL_TABLE_HPP #define GRNXX_IMPL_TABLE_HPP -#include "grnxx/name.hpp" +#include <cstdint> +#include <memory> + #include "grnxx/db.hpp" #include "grnxx/impl/column.hpp" #include "grnxx/table.hpp" @@ -13,75 +15,81 @@ using DBInterface = grnxx::DB; using TableInterface = grnxx::Table; class DB; +class TableRegularCursor; +class TableReverseCursor; class Table : public TableInterface { public: // -- Public API (grnxx/table.hpp) -- - Table(); + Table(DB *db, const String &name); ~Table(); DBInterface *db() const; - StringCRef name() const { - return name_.ref(); + String name() const { + return name_; } - Int num_columns() const { + size_t num_columns() const { return columns_.size(); } ColumnBase *key_column() const { return key_column_; } - Int num_rows() const { + size_t num_rows() const { return num_rows_; } Int max_row_id() const { return max_row_id_; } + bool is_empty() const { + return num_rows_ == 0; + } + bool is_full() const { + return is_empty() || + (num_rows_ == static_cast<size_t>(max_row_id_.value() + 1)); + } - ColumnBase *create_column(Error *error, - const StringCRef &name, + ColumnBase *create_column(const String &name, DataType data_type, const ColumnOptions &options = ColumnOptions()); - bool remove_column(Error *error, const StringCRef &name); - bool rename_column(Error *error, - const StringCRef &name, - const StringCRef &new_name); - bool reorder_column(Error *error, - const StringCRef &name, - const StringCRef &prev_name); - - ColumnBase *get_column(Int column_id) const { - return columns_[column_id].get(); + void remove_column(const String &name); + void rename_column(const String &name, const String &new_name); + void reorder_column(const String &name, const String &prev_name); + + ColumnBase *get_column(size_t i) const { + return columns_[i].get(); } - ColumnBase *find_column(Error *error, const StringCRef &name) const; + ColumnBase *find_column(const String &name) const; + + void set_key_column(const String &name); + void unset_key_column(); - bool set_key_column(Error *error, const StringCRef &name); - bool unset_key_column(Error *error); + Int insert_row(const Datum &key); + Int find_or_insert_row(const Datum &key, bool *inserted); + void insert_row_at(Int row_id, const Datum &key); - bool insert_row(Error *error, - Int request_row_id, - const Datum &key, - Int *result_row_id); - bool remove_row(Error *error, Int row_id); + void remove_row(Int row_id); - bool test_row(Error *error, Int row_id) const; - Int find_row(Error *error, const Datum &key) const; + bool test_row(Int row_id) const { + size_t bit_id = static_cast<size_t>(row_id.value()); + size_t block_id = bit_id / 64; + return (block_id < bitmap_.size()) && + ((bitmap_[block_id] & (uint64_t(1) << (bit_id % 64))) != 0); + } + Int find_row(const Datum &key) const; - unique_ptr<Cursor> create_cursor( - Error *error, + std::unique_ptr<Cursor> create_cursor( const CursorOptions &options = CursorOptions()) const; // -- Internal API -- // Create a new table. // - // On success, returns a pointer to the table. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<Table> create( - Error *error, + // On success, returns the table. + // On failure, throws an exception. + static std::unique_ptr<Table> create( DB *db, - const StringCRef &name, + const String &name, const TableOptions &options = TableOptions()); // Return the owner DB. @@ -89,68 +97,59 @@ class Table : public TableInterface { return db_; } + // Return whether a row is valid or not. + // + // If "row_id" is too large, the behavior is undefined. + bool _test_row(size_t row_id) const { + return (bitmap_[row_id / 64] & (uint64_t(1) << (row_id % 64))) != 0; + } + // Change the table name. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - bool rename(Error *error, const StringCRef &new_name); + // On failure, throws an exception. + void rename(const String &new_name); // Return whether the table is removable or not. - bool is_removable(); + bool is_removable() const; // Append a referrer column. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - bool append_referrer_column(Error *error, ColumnBase *column); + // On failure, throws an exception. + void append_referrer_column(ColumnBase *column); - // Append a referrer column. + // Remove a referrer column. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - bool remove_referrer_column(Error *error, ColumnBase *column); + // On failure, throws an exception. + void remove_referrer_column(ColumnBase *column); private: DB *db_; - Name name_; - Array<unique_ptr<ColumnBase>> columns_; + String name_; + Array<std::unique_ptr<ColumnBase>> columns_; Array<ColumnBase *> referrer_columns_; ColumnBase *key_column_; - Int num_rows_; + size_t num_rows_; Int max_row_id_; - Array<UInt> bitmap_; - Array<Array<UInt>> bitmap_indexes_; + Array<uint64_t> bitmap_; + Array<Array<uint64_t>> bitmap_indexes_; - // Get the "i"-th bit from the bitmap. - bool get_bit(Int i) const { - return (bitmap_[i / 64] & (Int(1) << (i % 64))) != 0; - } - // Set 1 to the "i"-th bit of the bitmap and update bitmap indexes. - void set_bit(Int i); - // Set 0 to the "i"-th bit of the bitmap and update bitmap indexes. - void unset_bit(Int i); - // Find a zero-bit and return its position. - Int find_zero_bit() const; - // Reserve the "i"-th bit for the next row. + // Find the next row ID candidate. + Int find_next_row_id() const; + // Reserve a row. // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - bool reserve_bit(Error *error, Int i); + // On failure, throws an exception. + void reserve_row(Int row_id); + // Validate a row. + void validate_row(Int row_id); + // Invalidate a row. + void invalidate_row(Int row_id); // Find a column with its ID. // - // On success, returns a pointer to the column. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - ColumnBase *find_column_with_id(Error *error, - const StringCRef &name, - Int *column_id) const; - - friend class TableCursor; + // If found, returns the column and stores its ID to "*column_id". + // If not found, returns nullptr. + ColumnBase *find_column_with_id(const String &name, + size_t *column_id) const; }; } // namespace impl Modified: test/Makefile.am (+12 -16) =================================================================== --- test/Makefile.am 2014-10-31 21:43:45 +0900 (0f3e534) +++ test/Makefile.am 2014-11-05 17:35:04 +0900 (0bb6481) @@ -1,11 +1,10 @@ TESTS = \ + test_array \ test_data_types \ - test_string + test_string \ + test_db \ + test_table -# test_string \ -# test_array \ -# test_db \ -# test_table \ # test_column \ # test_index \ # test_expression \ @@ -16,23 +15,20 @@ TESTS = \ check_PROGRAMS = $(TESTS) -test_data_types_SOURCES = test_data_types.cpp -test_data_types_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la - test_string_SOURCES = test_string.cpp test_string_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la -#test_string_SOURCES = test_string.cpp -#test_string_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la +test_array_SOURCES = test_array.cpp +test_array_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la -#test_array_SOURCES = test_array.cpp -#test_array_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la +test_data_types_SOURCES = test_data_types.cpp +test_data_types_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la -#test_db_SOURCES = test_db.cpp -#test_db_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la +test_db_SOURCES = test_db.cpp +test_db_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la -#test_table_SOURCES = test_table.cpp -#test_table_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la +test_table_SOURCES = test_table.cpp +test_table_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la #test_column_SOURCES = test_column.cpp #test_column_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la Modified: test/test_array.cpp (+79 -65) =================================================================== --- test/test_array.cpp 2014-10-31 21:43:45 +0900 (6f326a7) +++ test/test_array.cpp 2014-11-05 17:35:04 +0900 (f6d9292) @@ -20,128 +20,139 @@ #include <random> #include <vector> -#include "grnxx/types.hpp" +#include "grnxx/array.hpp" +#include "grnxx/data_types.hpp" std::mt19937_64 mersenne_twister; void test_bool() { - grnxx::Error error; - grnxx::Array<grnxx::Bool> array; assert(array.size() == 0); assert(array.capacity() == 0); - assert(array.push_back(&error, true)); + array.push_back(grnxx::Bool(true)); assert(array.size() == 1); - assert(array.capacity() == 64); + assert(array.capacity() == 1); assert(array[0]); - assert(array.push_back(&error, false)); + array.push_back(grnxx::Bool(false)); assert(array.size() == 2); - assert(array.capacity() == 64); + assert(array.capacity() == 2); assert(array[0]); assert(!array[1]); - assert(array.resize(&error, 200, true)); + array.push_back(grnxx::Bool(true)); + assert(array.size() == 3); + assert(array.capacity() == 4); + assert(array[0]); + assert(!array[1]); + assert(array[2]); + + array.resize(200, grnxx::Bool(true)); assert(array.size() == 200); - assert(array.capacity() == 256); + assert(array.capacity() == 200); assert(array[0]); assert(!array[1]); - for (grnxx::Int i = 2; i < 200; ++i) { - assert(array.get(i)); + assert(array[2]); + for (size_t i = 3; i < 200; ++i) { + assert(array[i]); } - constexpr grnxx::Int NUM_ROWS = 1 << 20; + constexpr size_t ARRAY_SIZE = 1 << 20; - assert(array.resize(&error, NUM_ROWS, false)); - assert(array.size() == NUM_ROWS); - assert(array.capacity() == NUM_ROWS); + array.resize(ARRAY_SIZE, grnxx::Bool(false)); + assert(array.size() == ARRAY_SIZE); + assert(array.capacity() == ARRAY_SIZE); assert(array[0]); assert(!array[1]); - for (grnxx::Int i = 2; i < 200; ++i) { - assert(array.get(i)); + assert(array[2]); + for (size_t i = 3; i < 200; ++i) { + assert(array[i]); } - for (grnxx::Int i = 200; i < NUM_ROWS; ++i) { - assert(!array.get(i)); + for (size_t i = 200; i < ARRAY_SIZE; ++i) { + assert(!array[i]); } - std::vector<grnxx::Bool> values(NUM_ROWS); - for (grnxx::Int i = 0; i < NUM_ROWS; ++i) { - values[i] = (mersenne_twister() & 1) != 0; + std::vector<grnxx::Bool> values(ARRAY_SIZE); + for (size_t i = 0; i < ARRAY_SIZE; ++i) { + values[i] = grnxx::Bool((mersenne_twister() & 1) != 0); array.set(i, values[i]); - assert(array[i] == values[i]); + assert(array.get(i) == values[i]); } - - for (grnxx::Int i = 0; i < NUM_ROWS; ++i) { - assert(array[i] == values[i]); + for (size_t i = 0; i < ARRAY_SIZE; ++i) { + assert(array.get(i) == values[i]); } grnxx::Array<grnxx::Bool> array2; array2 = std::move(array); assert(array.size() == 0); assert(array.capacity() == 0); - assert(array2.size() == NUM_ROWS); - assert(array2.capacity() == NUM_ROWS); + assert(array2.size() == ARRAY_SIZE); + assert(array2.capacity() == ARRAY_SIZE); + for (size_t i = 0; i < ARRAY_SIZE; ++i) { + assert(array2.get(i) == values[i]); + } } void test_int() { - grnxx::Error error; - grnxx::Array<grnxx::Int> array; assert(array.size() == 0); assert(array.capacity() == 0); - assert(array.push_back(&error, 123)); + array.push_back(grnxx::Int(123)); assert(array.size() == 1); assert(array.capacity() == 1); - assert(array[0] == 123); + assert(array[0] == grnxx::Int(123)); - assert(array.push_back(&error, 456)); + array.push_back(grnxx::Int(456)); assert(array.size() == 2); assert(array.capacity() == 2); - assert(array[0] == 123); - assert(array[1] == 456); + assert(array[0] == grnxx::Int(123)); + assert(array[1] == grnxx::Int(456)); - assert(array.push_back(&error, 789)); + array.push_back(grnxx::Int(789)); assert(array.size() == 3); assert(array.capacity() == 4); - assert(array[0] == 123); - assert(array[1] == 456); - assert(array[2] == 789); + assert(array[0] == grnxx::Int(123)); + assert(array[1] == grnxx::Int(456)); + assert(array[2] == grnxx::Int(789)); - assert(array.resize(&error, 200, 12345)); + array.resize(200, grnxx::Int(12345)); assert(array.size() == 200); assert(array.capacity() == 200); - assert(array[0] == 123); - assert(array[1] == 456); - assert(array[2] == 789); - for (grnxx::Int i = 3; i < 200; ++i) { - assert(array[i] == 12345); + assert(array[0] == grnxx::Int(123)); + assert(array[1] == grnxx::Int(456)); + assert(array[2] == grnxx::Int(789)); + for (size_t i = 3; i < 200; ++i) { + assert(array[i] == grnxx::Int(12345)); } - constexpr grnxx::Int NUM_ROWS = 1 << 20; + constexpr size_t ARRAY_SIZE = 1 << 20; - assert(array.resize(&error, NUM_ROWS, 0)); - assert(array.size() == NUM_ROWS); - assert(array.capacity() == NUM_ROWS); - assert(array[0] == 123); - assert(array[1] == 456); - assert(array[2] == 789); - for (grnxx::Int i = 3; i < 200; ++i) { - assert(array[i] == 12345); + array.resize(ARRAY_SIZE, grnxx::Int(0)); + assert(array.size() == ARRAY_SIZE); + assert(array.capacity() == ARRAY_SIZE); + assert(array[0] == grnxx::Int(123)); + assert(array[1] == grnxx::Int(456)); + assert(array[2] == grnxx::Int(789)); + for (size_t i = 3; i < 200; ++i) { + assert(array[i] == grnxx::Int(12345)); } - for (grnxx::Int i = 200; i < NUM_ROWS; ++i) { - assert(array[i] == 0); + for (size_t i = 200; i < ARRAY_SIZE; ++i) { + assert(array[i] == grnxx::Int(0)); } - std::vector<grnxx::Int> values(NUM_ROWS); - for (grnxx::Int i = 0; i < NUM_ROWS; ++i) { - values[i] = mersenne_twister(); - array[i] = values[i]; - assert(array[i] == values[i]); + std::vector<grnxx::Int> values(ARRAY_SIZE); + for (size_t i = 0; i < ARRAY_SIZE; ++i) { + grnxx::Int value = grnxx::Int(mersenne_twister()); + while (value.is_na()) { + value = grnxx::Int(mersenne_twister()); + } + values[i] = grnxx::Int(value); + array.set(i, values[i]); + assert(array.get(i) == values[i]); } - - for (grnxx::Int i = 0; i < NUM_ROWS; ++i) { + for (size_t i = 0; i < ARRAY_SIZE; ++i) { assert(array[i] == values[i]); } @@ -149,8 +160,11 @@ void test_int() { array2 = std::move(array); assert(array.size() == 0); assert(array.capacity() == 0); - assert(array2.size() == NUM_ROWS); - assert(array2.capacity() == NUM_ROWS); + assert(array2.size() == ARRAY_SIZE); + assert(array2.capacity() == ARRAY_SIZE); + for (size_t i = 0; i < ARRAY_SIZE; ++i) { + assert(array2[i] == values[i]); + } } int main() { Modified: test/test_db.cpp (+20 -17) =================================================================== --- test/test_db.cpp 2014-10-31 21:43:45 +0900 (2989bb1) +++ test/test_db.cpp 2014-11-05 17:35:04 +0900 (b757eba) @@ -22,54 +22,57 @@ #include "grnxx/table.hpp" void test_db() { - grnxx::Error error; - // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); + auto db = grnxx::open_db(""); assert(db->num_tables() == 0); // Create a table named "Table_1". - auto table = db->create_table(&error, "Table_1"); - assert(table); + auto table = db->create_table("Table_1"); assert(table->name() == "Table_1"); assert(db->num_tables() == 1); - assert(db->get_table(0) == table); - assert(db->find_table(&error, "Table_1") == table); + + assert(db->find_table("Table_1") == table); + assert(!db->find_table("Table_X")); // The following create_table() must fail because "Table_1" already exists. - assert(!db->create_table(&error, "Table_1")); + try { + db->create_table("Table_1"); + assert(false); + } catch (...) { + } // Create tables named "Table_2" and "Table_3". - assert(db->create_table(&error, "Table_2")); - assert(db->create_table(&error, "Table_3")); + assert(db->create_table("Table_2")); + assert(db->create_table("Table_3")); assert(db->num_tables() == 3); + assert(db->get_table(0)->name() == "Table_1"); + assert(db->get_table(1)->name() == "Table_2"); + assert(db->get_table(2)->name() == "Table_3"); // Remove "Table_2". - assert(db->remove_table(&error, "Table_2")); + db->remove_table("Table_2"); assert(db->num_tables() == 2); - assert(db->get_table(0)->name() == "Table_1"); assert(db->get_table(1)->name() == "Table_3"); // Recreate "Table_2". - assert(db->create_table(&error, "Table_2")); + assert(db->create_table("Table_2")); // Move "Table_3" to the next to "Table_2". - assert(db->reorder_table(&error, "Table_3", "Table_2")); + db->reorder_table("Table_3", "Table_2"); assert(db->get_table(0)->name() == "Table_1"); assert(db->get_table(1)->name() == "Table_2"); assert(db->get_table(2)->name() == "Table_3"); // Move "Table_3" to the head. - assert(db->reorder_table(&error, "Table_3", "")); + db->reorder_table("Table_3", ""); assert(db->get_table(0)->name() == "Table_3"); assert(db->get_table(1)->name() == "Table_1"); assert(db->get_table(2)->name() == "Table_2"); // Move "Table_2" to the next to "Table_3". - assert(db->reorder_table(&error, "Table_2", "Table_3")); + db->reorder_table("Table_2", "Table_3"); assert(db->get_table(0)->name() == "Table_3"); assert(db->get_table(1)->name() == "Table_2"); assert(db->get_table(2)->name() == "Table_1"); Modified: test/test_table.cpp (+460 -454) =================================================================== --- test/test_table.cpp 2014-10-31 21:43:45 +0900 (ad33788) +++ test/test_table.cpp 2014-11-05 17:35:04 +0900 (7d69b25) @@ -24,487 +24,493 @@ #include "grnxx/table.hpp" void test_table() { - grnxx::Error error; - // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); + auto db = grnxx::open_db(""); // Create a table named "Table". - auto table = db->create_table(&error, "Table"); - assert(table); + auto table = db->create_table("Table"); assert(table->db() == db.get()); assert(table->name() == "Table"); assert(table->num_columns() == 0); assert(!table->key_column()); assert(table->num_rows() == 0); - assert(table->max_row_id() == 0); - - // Create a column named "Column_1". - auto column = table->create_column(&error, "Column_1", grnxx::BOOL_DATA); - assert(column); - assert(column->name() == "Column_1"); - assert(table->num_columns() == 1); - - assert(table->get_column(0) == column); - assert(table->find_column(&error, "Column_1") == column); - - // The following create_column() must fail because "Column_1" already exists. - assert(!table->create_column(&error, "Column_1", grnxx::BOOL_DATA)); - - // Create columns named "Column_2" and Column_3". - assert(table->create_column(&error, "Column_2", grnxx::BOOL_DATA)); - assert(table->create_column(&error, "Column_3", grnxx::BOOL_DATA)); - assert(table->num_columns() == 3); - - // Remove "Column_2". - assert(table->remove_column(&error, "Column_2")); - assert(table->num_columns() == 2); - - assert(table->get_column(0)->name() == "Column_1"); - assert(table->get_column(1)->name() == "Column_3"); - - // Recreate "Column_2". - assert(table->create_column(&error, "Column_2", grnxx::BOOL_DATA)); - - // Move "Column_3" to the next to "Column_2". - assert(table->reorder_column(&error, "Column_3", "Column_2")); - assert(table->get_column(0)->name() == "Column_1"); - assert(table->get_column(1)->name() == "Column_2"); - assert(table->get_column(2)->name() == "Column_3"); - - // Move "Column_3" to the head. - assert(table->reorder_column(&error, "Column_3", "")); - assert(table->get_column(0)->name() == "Column_3"); - assert(table->get_column(1)->name() == "Column_1"); - assert(table->get_column(2)->name() == "Column_2"); - - // Move "Column_2" to the next to "Column3". - assert(table->reorder_column(&error, "Column_2", "Column_3")); - assert(table->get_column(0)->name() == "Column_3"); - assert(table->get_column(1)->name() == "Column_2"); - assert(table->get_column(2)->name() == "Column_1"); + assert(table->max_row_id().is_na()); + assert(table->is_empty()); + assert(table->is_full()); + +// // Create a column named "Column_1". +// auto column = table->create_column(&error, "Column_1", grnxx::BOOL_DATA); +// assert(column); +// assert(column->name() == "Column_1"); +// assert(table->num_columns() == 1); + +// assert(table->get_column(0) == column); +// assert(table->find_column(&error, "Column_1") == column); + +// // The following create_column() must fail because "Column_1" already exists. +// assert(!table->create_column(&error, "Column_1", grnxx::BOOL_DATA)); + +// // Create columns named "Column_2" and Column_3". +// assert(table->create_column(&error, "Column_2", grnxx::BOOL_DATA)); +// assert(table->create_column(&error, "Column_3", grnxx::BOOL_DATA)); +// assert(table->num_columns() == 3); + +// // Remove "Column_2". +// assert(table->remove_column(&error, "Column_2")); +// assert(table->num_columns() == 2); + +// assert(table->get_column(0)->name() == "Column_1"); +// assert(table->get_column(1)->name() == "Column_3"); + +// // Recreate "Column_2". +// assert(table->create_column(&error, "Column_2", grnxx::BOOL_DATA)); + +// // Move "Column_3" to the next to "Column_2". +// assert(table->reorder_column(&error, "Column_3", "Column_2")); +// assert(table->get_column(0)->name() == "Column_1"); +// assert(table->get_column(1)->name() == "Column_2"); +// assert(table->get_column(2)->name() == "Column_3"); + +// // Move "Column_3" to the head. +// assert(table->reorder_column(&error, "Column_3", "")); +// assert(table->get_column(0)->name() == "Column_3"); +// assert(table->get_column(1)->name() == "Column_1"); +// assert(table->get_column(2)->name() == "Column_2"); + +// // Move "Column_2" to the next to "Column3". +// assert(table->reorder_column(&error, "Column_2", "Column_3")); +// assert(table->get_column(0)->name() == "Column_3"); +// assert(table->get_column(1)->name() == "Column_2"); +// assert(table->get_column(2)->name() == "Column_1"); } void test_rows() { - grnxx::Error error; - // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); + auto db = grnxx::open_db(""); // Create a table named "Table". - auto table = db->create_table(&error, "Table"); - assert(table); + auto table = db->create_table("Table"); // Append the first row. grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(row_id == 1); + row_id = table->insert_row(); + assert(row_id == grnxx::Int(0)); assert(table->num_rows() == 1); - assert(table->max_row_id() == 1); - assert(!table->test_row(&error, 0)); - assert(table->test_row(&error, 1)); - assert(!table->test_row(&error, 2)); + assert(table->max_row_id() == row_id); + assert(!table->test_row(grnxx::Int(-1))); + assert(table->test_row(grnxx::Int(0))); + assert(!table->test_row(grnxx::Int(1))); // Append two more rows. - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(row_id == 3); + assert(table->insert_row() == grnxx::Int(1)); + assert(table->insert_row() == grnxx::Int(2)); assert(table->num_rows() == 3); - assert(table->max_row_id() == 3); - assert(!table->test_row(&error, 0)); - assert(table->test_row(&error, 1)); - assert(table->test_row(&error, 2)); - assert(table->test_row(&error, 3)); - assert(!table->test_row(&error, 4)); - - // Remove the 2nd row. - assert(table->remove_row(&error, 2)); + assert(table->max_row_id() == grnxx::Int(2)); + assert(table->test_row(grnxx::Int(0))); + assert(table->test_row(grnxx::Int(1))); + assert(table->test_row(grnxx::Int(2))); + assert(!table->test_row(grnxx::Int(3))); + + // Remove the second row. + table->remove_row(grnxx::Int(1)); assert(table->num_rows() == 2); - assert(table->max_row_id() == 3); - assert(!table->test_row(&error, 0)); - assert(table->test_row(&error, 1)); - assert(!table->test_row(&error, 2)); - assert(table->test_row(&error, 3)); - assert(!table->test_row(&error, 4)); -} - -void test_bitmap() { - constexpr int NUM_ROWS = 1 << 16; - - grnxx::Error error; - - // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); - - // Create a table named "Table". - auto table = db->create_table(&error, "Table"); - assert(table); - - // Create rows. - for (int i = 0; i < NUM_ROWS; ++i) { - grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(row_id == (i + 1)); - } - assert(table->num_rows() == NUM_ROWS); - assert(table->max_row_id() == NUM_ROWS); - - // Remove all rows. - for (int i = 0; i < NUM_ROWS; ++i) { - grnxx::Int row_id = i + 1; - assert(table->remove_row(&error, row_id)); - } + assert(table->max_row_id() == grnxx::Int(2)); + assert(table->test_row(grnxx::Int(0))); + assert(!table->test_row(grnxx::Int(1))); + assert(table->test_row(grnxx::Int(2))); + assert(!table->test_row(grnxx::Int(3))); + + // Remove the first row. + table->remove_row(grnxx::Int(0)); + assert(table->num_rows() == 1); + assert(table->max_row_id() == grnxx::Int(2)); + assert(!table->test_row(grnxx::Int(0))); + assert(!table->test_row(grnxx::Int(1))); + assert(table->test_row(grnxx::Int(2))); + assert(!table->test_row(grnxx::Int(3))); + + // Remove the third row. + table->remove_row(grnxx::Int(2)); assert(table->num_rows() == 0); - assert(table->max_row_id() == (grnxx::MIN_ROW_ID - 1)); - - // Recreate rows. - for (int i = 0; i < NUM_ROWS; ++i) { - grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(row_id == (i + 1)); - } - assert(table->num_rows() == NUM_ROWS); - assert(table->max_row_id() == NUM_ROWS); - - // Remove rows with odd IDs. - for (int i = 0; i < NUM_ROWS; i += 2) { - grnxx::Int row_id = i + 1; - assert(table->remove_row(&error, row_id)); - } - assert(table->num_rows() == (NUM_ROWS / 2)); - assert(table->max_row_id() == NUM_ROWS); - - // Recreate rows. - for (int i = 0; i < NUM_ROWS; i += 2) { - grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(row_id == (i + 1)); - } - assert(table->num_rows() == NUM_ROWS); - assert(table->max_row_id() == NUM_ROWS); - - // Remove rows in reverse order. - for (int i = 0; i < NUM_ROWS; ++i) { - grnxx::Int row_id = NUM_ROWS - i; - assert(table->remove_row(&error, row_id)); - assert(table->max_row_id() == (row_id - 1)); - } - - // Recreate rows. - for (int i = 0; i < NUM_ROWS; ++i) { - grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(row_id == (i + 1)); - } - assert(table->num_rows() == NUM_ROWS); - assert(table->max_row_id() == NUM_ROWS); + assert(table->max_row_id().is_na()); + assert(!table->test_row(grnxx::Int(0))); + assert(!table->test_row(grnxx::Int(1))); + assert(!table->test_row(grnxx::Int(2))); + assert(!table->test_row(grnxx::Int(3))); } -void test_int_key() { - // TODO: find_row() is not supported yet. - grnxx::Error error; - - // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); - - // Create a table named "Table". - auto table = db->create_table(&error, "Table"); - assert(table); - - // Create a column named "Column". - auto column = table->create_column(&error, "Column", grnxx::INT_DATA); - assert(column); - - // Append three rows. - grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(column->set(&error, row_id, grnxx::Int(1))); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(column->set(&error, row_id, grnxx::Int(10))); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(column->set(&error, row_id, grnxx::Int(100))); - - // Set key column. - assert(table->set_key_column(&error, "Column")); - assert(table->key_column() == column); - - // Duplicate keys must be rejected. - assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Int(1), &row_id)); - assert(row_id == 1); - assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Int(10), &row_id)); - assert(row_id == 2); - assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Int(100), &row_id)); - assert(row_id == 3); - - // Append new keys. - grnxx::Datum datum; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Int(2), &row_id)); - assert(column->get(&error, row_id, &datum)); - assert(datum.force_int() == 2); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Int(20), &row_id)); - assert(column->get(&error, row_id, &datum)); - assert(datum.force_int() == 20); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Int(200), &row_id)); - assert(column->get(&error, row_id, &datum)); - assert(datum.force_int() == 200); - - // Find rows by key. - assert(table->find_row(&error, grnxx::Int(1)) == 1); - assert(table->find_row(&error, grnxx::Int(10)) == 2); - assert(table->find_row(&error, grnxx::Int(100)) == 3); - assert(table->find_row(&error, grnxx::Int(2)) == 4); - assert(table->find_row(&error, grnxx::Int(20)) == 5); - assert(table->find_row(&error, grnxx::Int(200)) == 6); - - // Unset key column. - assert(table->unset_key_column(&error)); - assert(!table->key_column()); -} - -void test_text_key() { - // TODO: find_row() is not supported yet. - grnxx::Error error; - - // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); - - // Create a table named "Table". - auto table = db->create_table(&error, "Table"); - assert(table); - - // Create a column named "Column". - auto column = table->create_column(&error, "Column", grnxx::TEXT_DATA); - assert(column); - - // Append three rows. - grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(column->set(&error, row_id, grnxx::Text("1"))); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(column->set(&error, row_id, grnxx::Text("12"))); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(column->set(&error, row_id, grnxx::Text("123"))); - - // Set key column. - assert(table->set_key_column(&error, "Column")); - assert(table->key_column() == column); - - // Duplicate keys must be rejected. - assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Text("1"), &row_id)); - assert(row_id == 1); - assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Text("12"), &row_id)); - assert(row_id == 2); - assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Text("123"), &row_id)); - assert(row_id == 3); - - // Append new keys. - grnxx::Datum datum; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Text("A"), &row_id)); - assert(column->get(&error, row_id, &datum)); - assert(datum.force_text() == "A"); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Text("AB"), &row_id)); - assert(column->get(&error, row_id, &datum)); - assert(datum.force_text() == "AB"); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Text("ABC"), &row_id)); - assert(column->get(&error, row_id, &datum)); - assert(datum.force_text() == "ABC"); - - // Find rows by key. - assert(table->find_row(&error, grnxx::Text("1")) == 1); - assert(table->find_row(&error, grnxx::Text("12")) == 2); - assert(table->find_row(&error, grnxx::Text("123")) == 3); - assert(table->find_row(&error, grnxx::Text("A")) == 4); - assert(table->find_row(&error, grnxx::Text("AB")) == 5); - assert(table->find_row(&error, grnxx::Text("ABC")) == 6); - - // Unset key column. - assert(table->unset_key_column(&error)); - assert(!table->key_column()); -} - -void test_cursor() { - grnxx::Error error; - - // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); - - // Create a table named "Table". - auto table = db->create_table(&error, "Table"); - assert(table); - - // Create a column named "Column". - assert(table->create_column(&error, "Column", grnxx::BOOL_DATA)); - - // Append three rows and remove the 2nd row. - grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(table->remove_row(&error, 2)); - - // Create a cursor with the default options. - auto cursor = table->create_cursor(&error); - assert(cursor); - - // Read records from the cursor. - grnxx::Array<grnxx::Record> records; - auto result = cursor->read(&error, 0, &records); - assert(result.is_ok); - assert(result.count == 0); - - result = cursor->read(&error, 1, &records); - assert(result.is_ok); - assert(result.count == 1); - assert(records.size() == 1); - assert(records.get(0).row_id == 1); - - result = cursor->read(&error, 2, &records); - assert(result.is_ok); - assert(result.count == 1); - assert(records.size() == 2); - assert(records.get(0).row_id == 1); - assert(records.get(1).row_id == 3); - - records.clear(); - - // Create a cursor that scans a table in reverse order. - grnxx::CursorOptions cursor_options; - cursor_options.order_type = grnxx::REVERSE_ORDER; - cursor = table->create_cursor(&error, cursor_options); - assert(cursor); - - result = cursor->read_all(&error, &records); - assert(result.is_ok); - assert(result.count == 2); - assert(records.size() == 2); - assert(records.get(0).row_id == 3); - assert(records.get(1).row_id == 1); - - records.clear(); - - cursor = table->create_cursor(&error, cursor_options); - assert(cursor); - - result = cursor->read(&error, 1, &records); - assert(result.is_ok); - assert(result.count == 1); - assert(records.size() == 1); - assert(records.get(0).row_id == 3); - - result = cursor->read(&error, 2, &records); - assert(result.is_ok); - assert(result.count == 1); - assert(records.size() == 2); - assert(records.get(0).row_id == 3); - assert(records.get(1).row_id == 1); -} - -void test_reference() { - grnxx::Error error; - - // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); - - // Create a table named "Table". - auto to_table = db->create_table(&error, "To"); - assert(to_table); - auto from_table = db->create_table(&error, "From"); - assert(from_table); - - // Create a column named "Ref". - grnxx::ColumnOptions options; - options.ref_table_name = "To"; - auto ref_column = from_table->create_column(&error, "Ref", grnxx::INT_DATA, - options); - assert(ref_column); - - // Append rows. - grnxx::Int row_id; - assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - - assert(ref_column->set(&error, 1, grnxx::Int(1))); - assert(ref_column->set(&error, 2, grnxx::Int(2))); - assert(ref_column->set(&error, 3, grnxx::Int(2))); - - assert(to_table->remove_row(&error, 1)); - - grnxx::Datum datum; - assert(ref_column->get(&error, 1, &datum)); - assert(datum.type() == grnxx::INT_DATA); - assert(datum.force_int() == grnxx::NULL_ROW_ID); - assert(ref_column->get(&error, 2, &datum)); - assert(datum.type() == grnxx::INT_DATA); - assert(datum.force_int() == 2); - assert(ref_column->get(&error, 3, &datum)); - assert(datum.type() == grnxx::INT_DATA); - assert(datum.force_int() == 2); - - assert(to_table->remove_row(&error, 2)); - - assert(ref_column->get(&error, 1, &datum)); - assert(datum.type() == grnxx::INT_DATA); - assert(datum.force_int() == grnxx::NULL_ROW_ID); - assert(ref_column->get(&error, 2, &datum)); - assert(datum.type() == grnxx::INT_DATA); - assert(datum.force_int() == grnxx::NULL_ROW_ID); - assert(ref_column->get(&error, 3, &datum)); - assert(datum.type() == grnxx::INT_DATA); - assert(datum.force_int() == grnxx::NULL_ROW_ID); -} +//void test_bitmap() { +// constexpr int NUM_ROWS = 1 << 16; + +// grnxx::Error error; + +// // Create a database with the default options. +// auto db = grnxx::open_db(&error, ""); +// assert(db); + +// // Create a table named "Table". +// auto table = db->create_table(&error, "Table"); +// assert(table); + +// // Create rows. +// for (int i = 0; i < NUM_ROWS; ++i) { +// grnxx::Int row_id; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(row_id == (i + 1)); +// } +// assert(table->num_rows() == NUM_ROWS); +// assert(table->max_row_id() == NUM_ROWS); + +// // Remove all rows. +// for (int i = 0; i < NUM_ROWS; ++i) { +// grnxx::Int row_id = i + 1; +// assert(table->remove_row(&error, row_id)); +// } +// assert(table->num_rows() == 0); +// assert(table->max_row_id() == (grnxx::MIN_ROW_ID - 1)); + +// // Recreate rows. +// for (int i = 0; i < NUM_ROWS; ++i) { +// grnxx::Int row_id; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(row_id == (i + 1)); +// } +// assert(table->num_rows() == NUM_ROWS); +// assert(table->max_row_id() == NUM_ROWS); + +// // Remove rows with odd IDs. +// for (int i = 0; i < NUM_ROWS; i += 2) { +// grnxx::Int row_id = i + 1; +// assert(table->remove_row(&error, row_id)); +// } +// assert(table->num_rows() == (NUM_ROWS / 2)); +// assert(table->max_row_id() == NUM_ROWS); + +// // Recreate rows. +// for (int i = 0; i < NUM_ROWS; i += 2) { +// grnxx::Int row_id; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(row_id == (i + 1)); +// } +// assert(table->num_rows() == NUM_ROWS); +// assert(table->max_row_id() == NUM_ROWS); + +// // Remove rows in reverse order. +// for (int i = 0; i < NUM_ROWS; ++i) { +// grnxx::Int row_id = NUM_ROWS - i; +// assert(table->remove_row(&error, row_id)); +// assert(table->max_row_id() == (row_id - 1)); +// } + +// // Recreate rows. +// for (int i = 0; i < NUM_ROWS; ++i) { +// grnxx::Int row_id; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(row_id == (i + 1)); +// } +// assert(table->num_rows() == NUM_ROWS); +// assert(table->max_row_id() == NUM_ROWS); +//} + +//void test_int_key() { +// // TODO: find_row() is not supported yet. +// grnxx::Error error; + +// // Create a database with the default options. +// auto db = grnxx::open_db(&error, ""); +// assert(db); + +// // Create a table named "Table". +// auto table = db->create_table(&error, "Table"); +// assert(table); + +// // Create a column named "Column". +// auto column = table->create_column(&error, "Column", grnxx::INT_DATA); +// assert(column); + +// // Append three rows. +// grnxx::Int row_id; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(column->set(&error, row_id, grnxx::Int(1))); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(column->set(&error, row_id, grnxx::Int(10))); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(column->set(&error, row_id, grnxx::Int(100))); + +// // Set key column. +// assert(table->set_key_column(&error, "Column")); +// assert(table->key_column() == column); + +// // Duplicate keys must be rejected. +// assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Int(1), &row_id)); +// assert(row_id == 1); +// assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Int(10), &row_id)); +// assert(row_id == 2); +// assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Int(100), &row_id)); +// assert(row_id == 3); + +// // Append new keys. +// grnxx::Datum datum; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Int(2), &row_id)); +// assert(column->get(&error, row_id, &datum)); +// assert(datum.force_int() == 2); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Int(20), &row_id)); +// assert(column->get(&error, row_id, &datum)); +// assert(datum.force_int() == 20); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Int(200), &row_id)); +// assert(column->get(&error, row_id, &datum)); +// assert(datum.force_int() == 200); + +// // Find rows by key. +// assert(table->find_row(&error, grnxx::Int(1)) == 1); +// assert(table->find_row(&error, grnxx::Int(10)) == 2); +// assert(table->find_row(&error, grnxx::Int(100)) == 3); +// assert(table->find_row(&error, grnxx::Int(2)) == 4); +// assert(table->find_row(&error, grnxx::Int(20)) == 5); +// assert(table->find_row(&error, grnxx::Int(200)) == 6); + +// // Unset key column. +// assert(table->unset_key_column(&error)); +// assert(!table->key_column()); +//} + +//void test_text_key() { +// // TODO: find_row() is not supported yet. +// grnxx::Error error; + +// // Create a database with the default options. +// auto db = grnxx::open_db(&error, ""); +// assert(db); + +// // Create a table named "Table". +// auto table = db->create_table(&error, "Table"); +// assert(table); + +// // Create a column named "Column". +// auto column = table->create_column(&error, "Column", grnxx::TEXT_DATA); +// assert(column); + +// // Append three rows. +// grnxx::Int row_id; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(column->set(&error, row_id, grnxx::Text("1"))); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(column->set(&error, row_id, grnxx::Text("12"))); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(column->set(&error, row_id, grnxx::Text("123"))); + +// // Set key column. +// assert(table->set_key_column(&error, "Column")); +// assert(table->key_column() == column); + +// // Duplicate keys must be rejected. +// assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Text("1"), &row_id)); +// assert(row_id == 1); +// assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Text("12"), &row_id)); +// assert(row_id == 2); +// assert(!table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Text("123"), &row_id)); +// assert(row_id == 3); + +// // Append new keys. +// grnxx::Datum datum; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Text("A"), &row_id)); +// assert(column->get(&error, row_id, &datum)); +// assert(datum.force_text() == "A"); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Text("AB"), &row_id)); +// assert(column->get(&error, row_id, &datum)); +// assert(datum.force_text() == "AB"); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Text("ABC"), &row_id)); +// assert(column->get(&error, row_id, &datum)); +// assert(datum.force_text() == "ABC"); + +// // Find rows by key. +// assert(table->find_row(&error, grnxx::Text("1")) == 1); +// assert(table->find_row(&error, grnxx::Text("12")) == 2); +// assert(table->find_row(&error, grnxx::Text("123")) == 3); +// assert(table->find_row(&error, grnxx::Text("A")) == 4); +// assert(table->find_row(&error, grnxx::Text("AB")) == 5); +// assert(table->find_row(&error, grnxx::Text("ABC")) == 6); + +// // Unset key column. +// assert(table->unset_key_column(&error)); +// assert(!table->key_column()); +//} + +//void test_cursor() { +// grnxx::Error error; + +// // Create a database with the default options. +// auto db = grnxx::open_db(&error, ""); +// assert(db); + +// // Create a table named "Table". +// auto table = db->create_table(&error, "Table"); +// assert(table); + +// // Create a column named "Column". +// assert(table->create_column(&error, "Column", grnxx::BOOL_DATA)); + +// // Append three rows and remove the 2nd row. +// grnxx::Int row_id; +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(table->remove_row(&error, 2)); + +// // Create a cursor with the default options. +// auto cursor = table->create_cursor(&error); +// assert(cursor); + +// // Read records from the cursor. +// grnxx::Array<grnxx::Record> records; +// auto result = cursor->read(&error, 0, &records); +// assert(result.is_ok); +// assert(result.count == 0); + +// result = cursor->read(&error, 1, &records); +// assert(result.is_ok); +// assert(result.count == 1); +// assert(records.size() == 1); +// assert(records.get(0).row_id == 1); + +// result = cursor->read(&error, 2, &records); +// assert(result.is_ok); +// assert(result.count == 1); +// assert(records.size() == 2); +// assert(records.get(0).row_id == 1); +// assert(records.get(1).row_id == 3); + +// records.clear(); + +// // Create a cursor that scans a table in reverse order. +// grnxx::CursorOptions cursor_options; +// cursor_options.order_type = grnxx::REVERSE_ORDER; +// cursor = table->create_cursor(&error, cursor_options); +// assert(cursor); + +// result = cursor->read_all(&error, &records); +// assert(result.is_ok); +// assert(result.count == 2); +// assert(records.size() == 2); +// assert(records.get(0).row_id == 3); +// assert(records.get(1).row_id == 1); + +// records.clear(); + +// cursor = table->create_cursor(&error, cursor_options); +// assert(cursor); + +// result = cursor->read(&error, 1, &records); +// assert(result.is_ok); +// assert(result.count == 1); +// assert(records.size() == 1); +// assert(records.get(0).row_id == 3); + +// result = cursor->read(&error, 2, &records); +// assert(result.is_ok); +// assert(result.count == 1); +// assert(records.size() == 2); +// assert(records.get(0).row_id == 3); +// assert(records.get(1).row_id == 1); +//} + +//void test_reference() { +// grnxx::Error error; + +// // Create a database with the default options. +// auto db = grnxx::open_db(&error, ""); +// assert(db); + +// // Create a table named "Table". +// auto to_table = db->create_table(&error, "To"); +// assert(to_table); +// auto from_table = db->create_table(&error, "From"); +// assert(from_table); + +// // Create a column named "Ref". +// grnxx::ColumnOptions options; +// options.ref_table_name = "To"; +// auto ref_column = from_table->create_column(&error, "Ref", grnxx::INT_DATA, +// options); +// assert(ref_column); + +// // Append rows. +// grnxx::Int row_id; +// assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); +// assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID, +// grnxx::Datum(), &row_id)); + +// assert(ref_column->set(&error, 1, grnxx::Int(1))); +// assert(ref_column->set(&error, 2, grnxx::Int(2))); +// assert(ref_column->set(&error, 3, grnxx::Int(2))); + +// assert(to_table->remove_row(&error, 1)); + +// grnxx::Datum datum; +// assert(ref_column->get(&error, 1, &datum)); +// assert(datum.type() == grnxx::INT_DATA); +// assert(datum.force_int() == grnxx::NULL_ROW_ID); +// assert(ref_column->get(&error, 2, &datum)); +// assert(datum.type() == grnxx::INT_DATA); +// assert(datum.force_int() == 2); +// assert(ref_column->get(&error, 3, &datum)); +// assert(datum.type() == grnxx::INT_DATA); +// assert(datum.force_int() == 2); + +// assert(to_table->remove_row(&error, 2)); + +// assert(ref_column->get(&error, 1, &datum)); +// assert(datum.type() == grnxx::INT_DATA); +// assert(datum.force_int() == grnxx::NULL_ROW_ID); +// assert(ref_column->get(&error, 2, &datum)); +// assert(datum.type() == grnxx::INT_DATA); +// assert(datum.force_int() == grnxx::NULL_ROW_ID); +// assert(ref_column->get(&error, 3, &datum)); +// assert(datum.type() == grnxx::INT_DATA); +// assert(datum.force_int() == grnxx::NULL_ROW_ID); +//} int main() { test_table(); - test_rows(); - test_bitmap(); - test_int_key(); - test_text_key(); - test_cursor(); - test_reference(); +// test_rows(); +// test_bitmap(); +// test_int_key(); +// test_text_key(); +// test_cursor(); +// test_reference(); return 0; }