susumu.yata
null+****@clear*****
Tue Oct 7 13:33:14 JST 2014
susumu.yata 2014-10-07 13:33:14 +0900 (Tue, 07 Oct 2014) New Revision: 13bec8c270eed96f96487d345b1453fe654d8652 https://github.com/groonga/grnxx/commit/13bec8c270eed96f96487d345b1453fe654d8652 Message: Rename grnxx::ColumnImpl to grnxx::impl::Column. Added files: lib/grnxx/impl/column/column.cpp lib/grnxx/impl/column/column.hpp lib/grnxx/impl/column/column_bool.hpp lib/grnxx/impl/column/column_float.hpp lib/grnxx/impl/column/column_geo_point.hpp lib/grnxx/impl/column/column_int.cpp lib/grnxx/impl/column/column_int.hpp lib/grnxx/impl/column/column_text.cpp lib/grnxx/impl/column/column_text.hpp lib/grnxx/impl/column/column_vector_bool.hpp lib/grnxx/impl/column/column_vector_float.cpp lib/grnxx/impl/column/column_vector_float.hpp lib/grnxx/impl/column/column_vector_geo_point.cpp lib/grnxx/impl/column/column_vector_geo_point.hpp lib/grnxx/impl/column/column_vector_int.cpp lib/grnxx/impl/column/column_vector_int.hpp lib/grnxx/impl/column/column_vector_text.cpp lib/grnxx/impl/column/column_vector_text.hpp Removed files: lib/grnxx/column.cpp lib/grnxx/column_impl.hpp Modified files: lib/grnxx/Makefile.am lib/grnxx/expression.cpp lib/grnxx/impl/column.hpp lib/grnxx/impl/column/Makefile.am lib/grnxx/impl/column/column_base.cpp lib/grnxx/impl/column/column_base.hpp lib/grnxx/impl/table.hpp lib/grnxx/index.cpp Modified: lib/grnxx/Makefile.am (+0 -2) =================================================================== --- lib/grnxx/Makefile.am 2014-10-07 11:30:11 +0900 (6eba8e2) +++ lib/grnxx/Makefile.am 2014-10-07 13:33:14 +0900 (e7f9f19) @@ -10,7 +10,6 @@ libgrnxx_la_LDFLAGS = @AM_LTLDFLAGS@ libgrnxx_la_SOURCES = \ array.cpp \ - column.cpp \ cursor.cpp \ db.cpp \ error.cpp \ @@ -25,7 +24,6 @@ libgrnxx_la_SOURCES = \ libgrnxx_includedir = ${includedir}/grnxx libgrnxx_include_HEADERS = \ - column_impl.hpp \ name.hpp \ tree_index.hpp \ version.h Deleted: lib/grnxx/column.cpp (+0 -1055) 100644 =================================================================== --- lib/grnxx/column.cpp 2014-10-07 11:30:11 +0900 (cd4945e) +++ /dev/null @@ -1,1055 +0,0 @@ -#include "grnxx/column.hpp" - -#include "grnxx/column_impl.hpp" -#include "grnxx/cursor.hpp" -#include "grnxx/impl/db.hpp" -#include "grnxx/impl/table.hpp" -#include "grnxx/index.hpp" - -#include <set> -#include <unordered_set> - -namespace grnxx { - -// -- ColumnImpl<T> -- - -template <typename T> -bool ColumnImpl<T>::set(Error *error, Int row_id, const Datum &datum) { - if (datum.type() != TypeTraits<T>::data_type()) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); - return false; - } - if (!table_->test_row(error, row_id)) { - return false; - } - // Note that a Bool object does not have its own address. - T old_value = get(row_id); - T new_value; - datum.force(&new_value); - // TODO: Note that NaN != NaN. - if (new_value != old_value) { - for (Int i = 0; i < num_indexes(); ++i) { - if (!indexes_[i]->insert(error, row_id, datum)) { - for (Int j = 0; j < i; ++i) { - indexes_[j]->remove(nullptr, row_id, datum); - } - return false; - } - } - for (Int i = 0; i < num_indexes(); ++i) { - indexes_[i]->remove(nullptr, row_id, old_value); - } - } - values_.set(row_id, new_value); - return true; -} - -template <typename T> -bool ColumnImpl<T>::get(Error *error, Int row_id, Datum *datum) const { - if (!table_->test_row(error, row_id)) { - return false; - } - *datum = values_[row_id]; - return true; -} - -template <typename T> -unique_ptr<ColumnImpl<T>> ColumnImpl<T>::create(Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options) { - unique_ptr<ColumnImpl> column(new (nothrow) ColumnImpl); - if (!column) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - if (!column->initialize_base(error, table, name, - TypeTraits<T>::data_type(), options)) { - return nullptr; - } - if (!column->values_.resize(error, table->max_row_id() + 1, - TypeTraits<T>::default_value())) { - return nullptr; - } - return column; -} - -template <typename T> -ColumnImpl<T>::~ColumnImpl() {} - -template <typename T> -bool ColumnImpl<T>::set_default_value(Error *error, Int row_id) { - if (row_id >= values_.size()) { - if (!values_.resize(error, row_id + 1, TypeTraits<T>::default_value())) { - return false; - } - } - T value = TypeTraits<T>::default_value(); - for (Int i = 0; i < num_indexes(); ++i) { - if (!indexes_[i]->insert(error, row_id, value)) { - for (Int j = 0; j < i; ++j) { - indexes_[j]->remove(nullptr, row_id, value); - } - return false; - } - } - values_.set(row_id, value); - return true; -} - -template <typename T> -void ColumnImpl<T>::unset(Int row_id) { - for (Int i = 0; i < num_indexes(); ++i) { - indexes_[i]->remove(nullptr, row_id, get(row_id)); - } - values_.set(row_id, TypeTraits<T>::default_value()); -} - -template <typename T> -ColumnImpl<T>::ColumnImpl() : ColumnBase(), values_() {} - -template class ColumnImpl<Bool>; -template class ColumnImpl<Float>; -template class ColumnImpl<GeoPoint>; -template class ColumnImpl<Vector<Bool>>; - -// -- ColumnImpl<Int> -- - -bool ColumnImpl<Int>::set(Error *error, Int row_id, const Datum &datum) { - if (datum.type() != INT_DATA) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); - return false; - } - if (!table_->test_row(error, row_id)) { - return false; - } - if (ref_table_) { - if (!ref_table_->test_row(error, datum.force_int())) { - return false; - } - } - Int old_value = get(row_id); - Int new_value = datum.force_int(); - if (new_value != old_value) { - if (has_key_attribute_ && contains(datum)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate"); - return false; - } - for (Int i = 0; i < num_indexes(); ++i) { - if (!indexes_[i]->insert(error, row_id, datum)) { - for (Int j = 0; j < i; ++i) { - indexes_[j]->remove(nullptr, row_id, datum); - } - return false; - } - } - for (Int i = 0; i < num_indexes(); ++i) { - indexes_[i]->remove(nullptr, row_id, old_value); - } - } - values_.set(row_id, new_value); - return true; -} - -bool ColumnImpl<Int>::get(Error *error, Int row_id, Datum *datum) const { - if (!table_->test_row(error, row_id)) { - return false; - } - *datum = values_[row_id]; - return true; -} - -unique_ptr<ColumnImpl<Int>> ColumnImpl<Int>::create( - Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options) { - unique_ptr<ColumnImpl> column(new (nothrow) ColumnImpl); - if (!column) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - if (!column->initialize_base(error, table, name, INT_DATA, options)) { - return nullptr; - } - if (!column->values_.resize(error, table->max_row_id() + 1, - TypeTraits<Int>::default_value())) { - return nullptr; - } - if (column->ref_table()) { - if (!column->ref_table_->append_referrer_column(error, column.get())) { - return nullptr; - } - } - return column; -} - -ColumnImpl<Int>::~ColumnImpl() {} - -bool ColumnImpl<Int>::set_key_attribute(Error *error) { - if (has_key_attribute_) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This column is a key column"); - return false; - } - // TODO: An index should be used if possible. - try { - std::unordered_set<Int> set; - // TODO: Functor-based inline callback may be better in this case, - // because it does not require memory allocation. - auto cursor = table_->create_cursor(nullptr); - if (!cursor) { - return false; - } - Array<Record> records; - for ( ; ; ) { - auto result = cursor->read(nullptr, 1024, &records); - if (!result.is_ok) { - return false; - } else { - break; - } - for (Int i = 0; i < result.count; ++i) { - if (!set.insert(values_[records.get_row_id(i)]).second) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, "Key duplicate"); - return false; - } - } - records.clear(); - } - } catch (...) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return false; - } - has_key_attribute_ = true; - return true; -} - -bool ColumnImpl<Int>::unset_key_attribute(Error *error) { - if (!has_key_attribute_) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This column is not a key column"); - return false; - } - has_key_attribute_ = false; - return true; -} - -bool ColumnImpl<Int>::set_initial_key(Error *error, - Int row_id, - const Datum &key) { - if (!has_key_attribute_) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This column is not a key column"); - return false; - } - if (has_key_attribute_ && contains(key)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate"); - return false; - } - if (row_id >= values_.size()) { - if (!values_.resize(error, row_id + 1, TypeTraits<Int>::default_value())) { - return false; - } - } - Int value = key.force_int(); - for (Int i = 0; i < num_indexes(); ++i) { - if (!indexes_[i]->insert(error, row_id, value)) { - for (Int j = 0; j < i; ++j) { - indexes_[j]->remove(nullptr, row_id, value); - } - return false; - } - } - values_.set(row_id, value); - return true; -} - -bool ColumnImpl<Int>::set_default_value(Error *error, Int row_id) { - if (has_key_attribute_) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This column is a key column"); - return false; - } - if (row_id >= values_.size()) { - if (!values_.resize(error, row_id + 1, TypeTraits<Int>::default_value())) { - return false; - } - } - Int value = TypeTraits<Int>::default_value(); - for (Int i = 0; i < num_indexes(); ++i) { - if (!indexes_[i]->insert(error, row_id, value)) { - for (Int j = 0; j < i; ++j) { - indexes_[j]->remove(nullptr, row_id, value); - } - return false; - } - } - values_.set(row_id, value); - return true; -} - -void ColumnImpl<Int>::unset(Int row_id) { - for (Int i = 0; i < num_indexes(); ++i) { - indexes_[i]->remove(nullptr, row_id, get(row_id)); - } - values_.set(row_id, TypeTraits<Int>::default_value()); -} - -Int ColumnImpl<Int>::find_one(const Datum &datum) const { - // TODO: Cursor should not be used because it takes time. - // Also, cursor operations can fail due to memory allocation. - Int value = datum.force_int(); - if (indexes_.size() != 0) { - return indexes_[0]->find_one(datum); - } else { - // TODO: A full scan takes time. - // An index should be required for a key column. - - // TODO: Functor-based inline callback may be better in this case, - // because it does not require memory allocation. - - // Scan the column to find "value". - auto cursor = table_->create_cursor(nullptr); - if (!cursor) { - return NULL_ROW_ID; - } - Array<Record> records; - for ( ; ; ) { - auto result = cursor->read(nullptr, 1024, &records); - if (!result.is_ok || result.count == 0) { - return NULL_ROW_ID; - } - for (Int i = 0; i < result.count; ++i) { - if (values_[records.get_row_id(i)] == value) { - return records.get_row_id(i); - } - } - records.clear(); - } - } - return NULL_ROW_ID; -} - -void ColumnImpl<Int>::clear_references(Int row_id) { - // TODO: Cursor should not be used to avoid errors. - if (indexes_.size() != 0) { - auto cursor = indexes_[0]->find(nullptr, Int(0)); - if (!cursor) { - // Error. - return; - } - Array<Record> records; - for ( ; ; ) { - auto result = cursor->read(nullptr, 1024, &records); - if (!result.is_ok) { - // Error. - return; - } else if (result.count == 0) { - return; - } - for (Int i = 0; i < records.size(); ++i) { - set(nullptr, row_id, NULL_ROW_ID); - } - records.clear(); - } - } else { - auto cursor = table_->create_cursor(nullptr); - if (!cursor) { - // Error. - return; - } - Array<Record> records; - for ( ; ; ) { - auto result = cursor->read(nullptr, 1024, &records); - if (!result.is_ok) { - // Error. - return; - } else if (result.count == 0) { - return; - } - for (Int i = 0; i < records.size(); ++i) { - if (values_[records.get_row_id(i)] == row_id) { - values_[records.get_row_id(i)] = NULL_ROW_ID; - } - } - records.clear(); - } - } -} - -ColumnImpl<Int>::ColumnImpl() : ColumnBase(), values_() {} - -// -- ColumnImpl<Text> -- - -bool ColumnImpl<Text>::set(Error *error, Int row_id, const Datum &datum) { - if (datum.type() != TEXT_DATA) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); - return false; - } - if (!table_->test_row(error, row_id)) { - return false; - } - Text old_value = get(row_id); - Text new_value = datum.force_text(); - if (new_value != old_value) { - if (has_key_attribute_ && contains(datum)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate"); - return false; - } - for (Int i = 0; i < num_indexes(); ++i) { - if (!indexes_[i]->insert(error, row_id, datum)) { - for (Int j = 0; j < i; ++i) { - indexes_[j]->remove(nullptr, row_id, datum); - } - return false; - } - } - Int offset = bodies_.size(); - UInt new_header; - if (new_value.size() < 0xFFFF) { - if (!bodies_.resize(error, offset + new_value.size())) { - return false; - } - std::memcpy(&bodies_[offset], new_value.data(), new_value.size()); - new_header = (offset << 16) | new_value.size(); - } else { - // The size of a long text is stored in front of the body. - if ((offset % sizeof(Int)) != 0) { - offset += sizeof(Int) - (offset % sizeof(Int)); - } - if (!bodies_.resize(error, offset + sizeof(Int) + new_value.size())) { - return false; - } - *reinterpret_cast<Int *>(&bodies_[offset]) = new_value.size(); - std::memcpy(&bodies_[offset + sizeof(Int)], - new_value.data(), new_value.size()); - new_header = (offset << 16) | 0xFFFF; - } - for (Int i = 0; i < num_indexes(); ++i) { - indexes_[i]->remove(nullptr, row_id, old_value); - } - headers_[row_id] = new_header; - } - return true; -} - -bool ColumnImpl<Text>::get(Error *error, Int row_id, Datum *datum) const { - if (!table_->test_row(error, row_id)) { - return false; - } - *datum = get(row_id); - return true; -} - -unique_ptr<ColumnImpl<Text>> ColumnImpl<Text>::create( - Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options) { - unique_ptr<ColumnImpl> column(new (nothrow) ColumnImpl); - if (!column) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - if (!column->initialize_base(error, table, name, TEXT_DATA, options)) { - return nullptr; - } - if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) { - return nullptr; - } - return column; -} - -ColumnImpl<Text>::~ColumnImpl() {} - -bool ColumnImpl<Text>::set_key_attribute(Error *error) { - if (has_key_attribute_) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This column is a key column"); - return false; - } - // TODO: An index should be used if possible. - try { - std::set<Text> set; - // TODO: Functor-based inline callback may be better in this case, - // because it does not require memory allocation. - auto cursor = table_->create_cursor(nullptr); - if (!cursor) { - return false; - } - Array<Record> records; - for ( ; ; ) { - auto result = cursor->read(nullptr, 1024, &records); - if (!result.is_ok) { - return false; - } else { - break; - } - for (Int i = 0; i < result.count; ++i) { - if (!set.insert(get(records.get_row_id(i))).second) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, "Key duplicate"); - return false; - } - } - records.clear(); - } - } catch (...) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return false; - } - has_key_attribute_ = true; - return true; -} - -bool ColumnImpl<Text>::unset_key_attribute(Error *error) { - if (!has_key_attribute_) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This column is not a key column"); - return false; - } - has_key_attribute_ = false; - return true; -} - -bool ColumnImpl<Text>::set_initial_key(Error *error, - Int row_id, - const Datum &key) { - if (!has_key_attribute_) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This column is not a key column"); - return false; - } - if (has_key_attribute_ && contains(key)) { - GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate"); - return false; - } - if (row_id >= headers_.size()) { - if (!headers_.resize(error, row_id + 1, 0)) { - return false; - } - } - Text value = key.force_text(); - for (Int i = 0; i < num_indexes(); ++i) { - if (!indexes_[i]->insert(error, row_id, value)) { - for (Int j = 0; j < i; ++j) { - indexes_[j]->remove(nullptr, row_id, value); - } - return false; - } - } - Int offset = bodies_.size(); - UInt header; - if (value.size() < 0xFFFF) { - if (!bodies_.resize(error, offset + value.size())) { - return false; - } - std::memcpy(&bodies_[offset], value.data(), value.size()); - header = (offset << 16) | value.size(); - } else { - // The size of a long text is stored in front of the body. - if ((offset % sizeof(Int)) != 0) { - offset += sizeof(Int) - (offset % sizeof(Int)); - } - if (!bodies_.resize(error, offset + sizeof(Int) + value.size())) { - return false; - } - *reinterpret_cast<Int *>(&bodies_[offset]) = value.size(); - std::memcpy(&bodies_[offset + sizeof(Int)], value.data(), value.size()); - header = (offset << 16) | 0xFFFF; - } - headers_[row_id] = header; - return true; -} - -bool ColumnImpl<Text>::set_default_value(Error *error, Int row_id) { - if (has_key_attribute_) { - GRNXX_ERROR_SET(error, INVALID_OPERATION, - "This column is a key column"); - return false; - } - if (row_id >= headers_.size()) { - if (!headers_.resize(error, row_id + 1)) { - return false; - } - } - Text value = TypeTraits<Text>::default_value(); - for (Int i = 0; i < num_indexes(); ++i) { - if (!indexes_[i]->insert(error, row_id, value)) { - for (Int j = 0; j < i; ++j) { - indexes_[j]->remove(nullptr, row_id, value); - } - return false; - } - } - headers_[row_id] = 0; - return true; -} - -void ColumnImpl<Text>::unset(Int row_id) { - for (Int i = 0; i < num_indexes(); ++i) { - indexes_[i]->remove(nullptr, row_id, get(row_id)); - } - headers_[row_id] = 0; -} - -Int ColumnImpl<Text>::find_one(const Datum &datum) const { - // TODO: Cursor should not be used because it takes time. - // Also, cursor operations can fail due to memory allocation. - Text value = datum.force_text(); - if (indexes_.size() != 0) { - auto cursor = indexes_[0]->find(nullptr, value); - Array<Record> records; - auto result = cursor->read(nullptr, 1, &records); - if (!result.is_ok || (result.count == 0)) { - return NULL_ROW_ID; - } - return true; - } else { - // TODO: A full scan takes time. - // An index should be required for a key column. - - // TODO: Functor-based inline callback may be better in this case, - // because it does not require memory allocation. - - // Scan the column to find "value". - auto cursor = table_->create_cursor(nullptr); - if (!cursor) { - return NULL_ROW_ID; - } - Array<Record> records; - for ( ; ; ) { - auto result = cursor->read(nullptr, 1024, &records); - if (!result.is_ok || result.count == 0) { - return NULL_ROW_ID; - } - for (Int i = 0; i < result.count; ++i) { - if (get(records.get_row_id(i)) == value) { - return records.get_row_id(i); - } - } - records.clear(); - } - } - return NULL_ROW_ID; -} - -ColumnImpl<Text>::ColumnImpl() : ColumnBase(), headers_(), bodies_() {} - -// -- ColumnImpl<Vector<Int>> -- - -bool ColumnImpl<Vector<Int>>::set(Error *error, Int row_id, - const Datum &datum) { - if (datum.type() != INT_VECTOR_DATA) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); - return false; - } - if (!table_->test_row(error, row_id)) { - return false; - } - Vector<Int> value = datum.force_int_vector(); - if (value.size() == 0) { - headers_[row_id] = 0; - return true; - } - if (ref_table_) { - for (Int i = 0; i < value.size(); ++i) { - if (!ref_table_->test_row(error, value[i])) { - return false; - } - } - } - Int offset = bodies_.size(); - if (value.size() < 0xFFFF) { - if (!bodies_.resize(error, offset + value.size())) { - return false; - } - for (Int i = 0; i < value.size(); ++i) { - bodies_[offset + i] = value[i]; - } - headers_[row_id] = (offset << 16) | value.size(); - } else { - // The size of a long vector is stored in front of the body. - if (!bodies_.resize(error, offset + 1 + value.size())) { - return false; - } - bodies_[offset] = value.size(); - for (Int i = 0; i < value.size(); ++i) { - bodies_[offset + 1 + i] = value[i]; - } - headers_[row_id] = (offset << 16) | 0xFFFF; - } - return true; -} - -bool ColumnImpl<Vector<Int>>::get(Error *error, Int row_id, - Datum *datum) const { - if (!table_->test_row(error, row_id)) { - return false; - } - *datum = get(row_id); - return true; -} - -unique_ptr<ColumnImpl<Vector<Int>>> ColumnImpl<Vector<Int>>::create( - Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options) { - unique_ptr<ColumnImpl> column(new (nothrow) ColumnImpl); - if (!column) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - if (!column->initialize_base(error, table, name, INT_VECTOR_DATA, options)) { - return nullptr; - } - if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) { - return nullptr; - } - if (column->ref_table()) { - if (!column->ref_table_->append_referrer_column(error, column.get())) { - return nullptr; - } - } - return column; -} - -ColumnImpl<Vector<Int>>::~ColumnImpl() {} - -bool ColumnImpl<Vector<Int>>::set_default_value(Error *error, Int row_id) { - if (row_id >= headers_.size()) { - if (!headers_.resize(error, row_id + 1)) { - return false; - } - } - headers_[row_id] = 0; - return true; -} - -void ColumnImpl<Vector<Int>>::unset(Int row_id) { - headers_[row_id] = 0; -} - -void ColumnImpl<Vector<Int>>::clear_references(Int row_id) { - auto cursor = table_->create_cursor(nullptr); - if (!cursor) { - // Error. - return; - } - Array<Record> records; - for ( ; ; ) { - auto result = cursor->read(nullptr, 1024, &records); - if (!result.is_ok) { - // Error. - return; - } else if (result.count == 0) { - return; - } - for (Int i = 0; i < records.size(); ++i) { - Int value_row_id = records.get_row_id(i); - Int value_size = static_cast<Int>(headers_[value_row_id] & 0xFFFF); - if (value_size == 0) { - continue; - } - Int value_offset = static_cast<Int>(headers_[value_row_id] >> 16); - if (value_size >= 0xFFFF) { - value_size = bodies_[value_offset]; - ++value_offset; - } - Int count = 0; - for (Int j = 0; j < value_size; ++j) { - if (bodies_[value_offset + j] != row_id) { - bodies_[value_offset + count] = bodies_[value_offset + j]; - ++count; - } - } - if (count < value_size) { - if (count == 0) { - headers_[value_row_id] = 0; - } else if (count < 0xFFFF) { - headers_[value_row_id] = count | (value_offset << 16); - } else { - bodies_[value_offset - 1] = count; - } - } - } - records.clear(); - } -} - -ColumnImpl<Vector<Int>>::ColumnImpl() : ColumnBase(), headers_(), bodies_() {} - -// -- ColumnImpl<Vector<Float>> -- - -bool ColumnImpl<Vector<Float>>::set(Error *error, Int row_id, - const Datum &datum) { - if (datum.type() != FLOAT_VECTOR_DATA) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); - return false; - } - if (!table_->test_row(error, row_id)) { - return false; - } - Vector<Float> value = datum.force_float_vector(); - if (value.size() == 0) { - headers_[row_id] = 0; - return true; - } - Int offset = bodies_.size(); - if (value.size() < 0xFFFF) { - if (!bodies_.resize(error, offset + value.size())) { - return false; - } - for (Int i = 0; i < value.size(); ++i) { - bodies_[offset + i] = value[i]; - } - headers_[row_id] = (offset << 16) | value.size(); - } else { - // The size of a long vector is stored in front of the body. - if (!bodies_.resize(error, offset + 1 + value.size())) { - return false; - } - Int size_for_copy = value.size(); - std::memcpy(&bodies_[offset], &size_for_copy, sizeof(Int)); - for (Int i = 0; i < value.size(); ++i) { - bodies_[offset + 1 + i] = value[i]; - } - headers_[row_id] = (offset << 16) | 0xFFFF; - } - return true; -} - -bool ColumnImpl<Vector<Float>>::get(Error *error, Int row_id, - Datum *datum) const { - if (!table_->test_row(error, row_id)) { - return false; - } - *datum = get(row_id); - return true; -} - -unique_ptr<ColumnImpl<Vector<Float>>> ColumnImpl<Vector<Float>>::create( - Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options) { - unique_ptr<ColumnImpl> column(new (nothrow) ColumnImpl); - if (!column) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - if (!column->initialize_base(error, table, name, - FLOAT_VECTOR_DATA, options)) { - return nullptr; - } - if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) { - return nullptr; - } - return column; -} - -ColumnImpl<Vector<Float>>::~ColumnImpl() {} - -bool ColumnImpl<Vector<Float>>::set_default_value(Error *error, Int row_id) { - if (row_id >= headers_.size()) { - if (!headers_.resize(error, row_id + 1)) { - return false; - } - } - headers_[row_id] = 0; - return true; -} - -void ColumnImpl<Vector<Float>>::unset(Int row_id) { - headers_[row_id] = 0; -} - -ColumnImpl<Vector<Float>>::ColumnImpl() - : ColumnBase(), - headers_(), - bodies_() {} - -// -- ColumnImpl<Vector<GeoPoint>> -- - -bool ColumnImpl<Vector<GeoPoint>>::set(Error *error, Int row_id, - const Datum &datum) { - if (datum.type() != GEO_POINT_VECTOR_DATA) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); - return false; - } - if (!table_->test_row(error, row_id)) { - return false; - } - Vector<GeoPoint> value = datum.force_geo_point_vector(); - if (value.size() == 0) { - headers_[row_id] = 0; - return true; - } - Int offset = bodies_.size(); - if (value.size() < 0xFFFF) { - if (!bodies_.resize(error, offset + value.size())) { - return false; - } - for (Int i = 0; i < value.size(); ++i) { - bodies_[offset + i] = value[i]; - } - headers_[row_id] = (offset << 16) | value.size(); - } else { - // The size of a long vector is stored in front of the body. - if (!bodies_.resize(error, offset + 1 + value.size())) { - return false; - } - Int size_for_copy = value.size(); - std::memcpy(&bodies_[offset], &size_for_copy, sizeof(Int)); - for (Int i = 0; i < value.size(); ++i) { - bodies_[offset + 1 + i] = value[i]; - } - headers_[row_id] = (offset << 16) | 0xFFFF; - } - return true; -} - -bool ColumnImpl<Vector<GeoPoint>>::get(Error *error, Int row_id, - Datum *datum) const { - if (!table_->test_row(error, row_id)) { - return false; - } - *datum = get(row_id); - return true; -} - -unique_ptr<ColumnImpl<Vector<GeoPoint>>> ColumnImpl<Vector<GeoPoint>>::create( - Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options) { - unique_ptr<ColumnImpl> column(new (nothrow) ColumnImpl); - if (!column) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - if (!column->initialize_base(error, table, name, - GEO_POINT_VECTOR_DATA, options)) { - return nullptr; - } - if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) { - return nullptr; - } - return column; -} - -ColumnImpl<Vector<GeoPoint>>::~ColumnImpl() {} - -bool ColumnImpl<Vector<GeoPoint>>::set_default_value(Error *error, - Int row_id) { - if (row_id >= headers_.size()) { - if (!headers_.resize(error, row_id + 1)) { - return false; - } - } - headers_[row_id] = 0; - return true; -} - -void ColumnImpl<Vector<GeoPoint>>::unset(Int row_id) { - headers_[row_id] = 0; -} - -ColumnImpl<Vector<GeoPoint>>::ColumnImpl() - : ColumnBase(), - headers_(), - bodies_() {} - -// -- ColumnImpl<Vector<Text>> -- - -bool ColumnImpl<Vector<Text>>::set(Error *error, Int row_id, - const Datum &datum) { - if (datum.type() != TEXT_VECTOR_DATA) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); - return false; - } - if (!table_->test_row(error, row_id)) { - return false; - } - Vector<Text> value = datum.force_text_vector(); - if (value.size() == 0) { - headers_[row_id] = Header{ 0, 0 }; - return true; - } - Int text_headers_offset = text_headers_.size(); - if (!text_headers_.resize(error, text_headers_offset + value.size())) { - return false; - } - Int total_size = 0; - for (Int i = 0; i < value.size(); ++i) { - total_size += value[i].size(); - } - Int bodies_offset = bodies_.size(); - if (!bodies_.resize(error, bodies_offset + total_size)) { - return false; - } - headers_[row_id] = Header{ text_headers_offset, value.size() }; - for (Int i = 0; i < value.size(); ++i) { - text_headers_[text_headers_offset + i].offset = bodies_offset; - text_headers_[text_headers_offset + i].size = value[i].size(); - std::memcpy(&bodies_[bodies_offset], value[i].data(), value[i].size()); - bodies_offset += value[i].size(); - } - return true; -} - -bool ColumnImpl<Vector<Text>>::get(Error *error, Int row_id, - Datum *datum) const { - if (!table_->test_row(error, row_id)) { - return false; - } - *datum = get(row_id); - return true; -} - -unique_ptr<ColumnImpl<Vector<Text>>> ColumnImpl<Vector<Text>>::create( - Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options) { - unique_ptr<ColumnImpl> column(new (nothrow) ColumnImpl); - if (!column) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - if (!column->initialize_base(error, table, name, - TEXT_VECTOR_DATA, options)) { - return nullptr; - } - if (!column->headers_.resize(error, table->max_row_id() + 1, - Header{ 0, 0 })) { - return nullptr; - } - return column; -} - -ColumnImpl<Vector<Text>>::~ColumnImpl() {} - -bool ColumnImpl<Vector<Text>>::set_default_value(Error *error, - Int row_id) { - if (row_id >= headers_.size()) { - if (!headers_.resize(error, row_id + 1)) { - return false; - } - } - headers_[row_id] = Header{ 0, 0 }; - return true; -} - -void ColumnImpl<Vector<Text>>::unset(Int row_id) { - headers_[row_id] = Header{ 0, 0 }; -} - -ColumnImpl<Vector<Text>>::ColumnImpl() - : ColumnBase(), - headers_(), - text_headers_(), - bodies_() {} - -} // namespace grnxx Deleted: lib/grnxx/column_impl.hpp (+0 -396) 100644 =================================================================== --- lib/grnxx/column_impl.hpp 2014-10-07 11:30:11 +0900 (68b5a6c) +++ /dev/null @@ -1,396 +0,0 @@ -#ifndef GRNXX_COLUMN_IMPL_HPP -#define GRNXX_COLUMN_IMPL_HPP - -#include "grnxx/impl/column/column_base.hpp" - -namespace grnxx { - -template <typename T> -class ColumnImpl : public impl::ColumnBase { - public: - // -- Public API -- - - bool set(Error *error, Int row_id, const Datum &datum); - bool get(Error *error, Int row_id, Datum *datum) const; - - // -- Internal API -- - - // Create a new column. - // - // Returns a pointer to the column on success. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<ColumnImpl> create(Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options); - - ~ColumnImpl(); - - bool set_default_value(Error *error, Int row_id); - void unset(Int row_id); - - // Return a value identified by "row_id". - // - // Assumes that "row_id" is valid. Otherwise, the result is undefined. - T get(Int row_id) const { - return values_[row_id]; - } - - // Read values. - void read(ArrayCRef<Record> records, ArrayRef<T> values) const { - for (Int i = 0; i < records.size(); ++i) { - values.set(i, get(records.get_row_id(i))); - } - } - - private: - Array<T> values_; - - ColumnImpl(); -}; - -template <> -class ColumnImpl<Int> : public impl::ColumnBase { - public: - // -- Public API -- - - bool set(Error *error, Int row_id, const Datum &datum); - bool get(Error *error, Int row_id, Datum *datum) const; - - // -- Internal API -- - - // Create a new column. - // - // Returns a pointer to the column on success. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<ColumnImpl> create(Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options); - - ~ColumnImpl(); - - bool set_key_attribute(Error *error); - bool unset_key_attribute(Error *error); - - bool set_initial_key(Error *error, Int row_id, const Datum &key); - bool set_default_value(Error *error, Int row_id); - void unset(Int row_id); - Int find_one(const Datum &datum) const; - - void clear_references(Int row_id); - - // Return a value identified by "row_id". - // - // Assumes that "row_id" is valid. Otherwise, the result is undefined. - Int get(Int row_id) const { - return values_[row_id]; - } - - // Read values. - void read(ArrayCRef<Record> records, ArrayRef<Int> values) const { - for (Int i = 0; i < records.size(); ++i) { - values.set(i, get(records.get_row_id(i))); - } - } - - private: - Array<Int> values_; - - ColumnImpl(); -}; - -template <> -class ColumnImpl<Text> : public impl::ColumnBase { - public: - // -- Public API -- - - bool set(Error *error, Int row_id, const Datum &datum); - bool get(Error *error, Int row_id, Datum *datum) const; - - // -- Internal API -- - - // Create a new column. - // - // Returns a pointer to the column on success. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<ColumnImpl> create(Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options); - - ~ColumnImpl(); - - bool set_key_attribute(Error *error); - bool unset_key_attribute(Error *error); - - bool set_initial_key(Error *error, Int row_id, const Datum &key); - bool set_default_value(Error *error, Int row_id); - void unset(Int row_id); - Int find_one(const Datum &datum) const; - - // Return a value identified by "row_id". - // - // Assumes that "row_id" is valid. Otherwise, the result is undefined. - Text get(Int row_id) const { - Int size = static_cast<Int>(headers_[row_id] & 0xFFFF); - if (size == 0) { - return Text("", 0); - } - Int offset = static_cast<Int>(headers_[row_id] >> 16); - if (size < 0xFFFF) { - return Text(&bodies_[offset], size); - } else { - // The size of a long text is stored in front of the body. - size = *reinterpret_cast<const Int *>(&bodies_[offset]); - return StringCRef(&bodies_[offset + sizeof(Int)], size); - } - } - - // Read values. - void read(ArrayCRef<Record> records, ArrayRef<Text> values) const { - for (Int i = 0; i < records.size(); ++i) { - values.set(i, get(records.get_row_id(i))); - } - } - - private: - Array<UInt> headers_; - Array<char> bodies_; - - ColumnImpl(); -}; - -template <> -class ColumnImpl<Vector<Int>> : public impl::ColumnBase { - public: - // -- Public API -- - - bool set(Error *error, Int row_id, const Datum &datum); - bool get(Error *error, Int row_id, Datum *datum) const; - - // -- Internal API -- - - // Create a new column. - // - // Returns a pointer to the column on success. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<ColumnImpl> create(Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options); - - ~ColumnImpl(); - - bool set_default_value(Error *error, Int row_id); - void unset(Int row_id); - - void clear_references(Int row_id); - - // Return a value identified by "row_id". - // - // Assumes that "row_id" is valid. Otherwise, the result is undefined. - Vector<Int> get(Int row_id) const { - Int size = static_cast<Int>(headers_[row_id] & 0xFFFF); - if (size == 0) { - return Vector<Int>(nullptr, 0); - } - Int offset = static_cast<Int>(headers_[row_id] >> 16); - if (size < 0xFFFF) { - return Vector<Int>(&bodies_[offset], size); - } else { - // The size of a long vector is stored in front of the body. - size = bodies_[offset]; - return Vector<Int>(&bodies_[offset + 1], size); - } - } - - // Read values. - void read(ArrayCRef<Record> records, ArrayRef<Vector<Int>> values) const { - for (Int i = 0; i < records.size(); ++i) { - values.set(i, get(records.get_row_id(i))); - } - } - - private: - Array<UInt> headers_; - Array<Int> bodies_; - - ColumnImpl(); -}; - -template <> -class ColumnImpl<Vector<Float>> : public impl::ColumnBase { - public: - // -- Public API -- - - bool set(Error *error, Int row_id, const Datum &datum); - bool get(Error *error, Int row_id, Datum *datum) const; - - // -- Internal API -- - - // Create a new column. - // - // Returns a pointer to the column on success. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<ColumnImpl> create(Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options); - - ~ColumnImpl(); - - bool set_default_value(Error *error, Int row_id); - void unset(Int row_id); - - // Return a value identified by "row_id". - // - // Assumes that "row_id" is valid. Otherwise, the result is undefined. - Vector<Float> get(Int row_id) const { - Int size = static_cast<Int>(headers_[row_id] & 0xFFFF); - if (size == 0) { - return Vector<Float>(nullptr, 0); - } - Int offset = static_cast<Int>(headers_[row_id] >> 16); - if (size < 0xFFFF) { - return Vector<Float>(&bodies_[offset], size); - } else { - // The size of a long vector is stored in front of the body. - std::memcpy(&size, &bodies_[offset], sizeof(Int)); - return Vector<Float>(&bodies_[offset + 1], size); - } - } - - // Read values. - void read(ArrayCRef<Record> records, ArrayRef<Vector<Float>> values) const { - for (Int i = 0; i < records.size(); ++i) { - values.set(i, get(records.get_row_id(i))); - } - } - - private: - Array<UInt> headers_; - Array<Float> bodies_; - - ColumnImpl(); -}; - -template <> -class ColumnImpl<Vector<GeoPoint>> : public impl::ColumnBase { - public: - // -- Public API -- - - bool set(Error *error, Int row_id, const Datum &datum); - bool get(Error *error, Int row_id, Datum *datum) const; - - // -- Internal API -- - - // Create a new column. - // - // Returns a pointer to the column on success. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<ColumnImpl> create(Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options); - - ~ColumnImpl(); - - bool set_default_value(Error *error, Int row_id); - void unset(Int row_id); - - // Return a value identified by "row_id". - // - // Assumes that "row_id" is valid. Otherwise, the result is undefined. - Vector<GeoPoint> get(Int row_id) const { - Int size = static_cast<Int>(headers_[row_id] & 0xFFFF); - if (size == 0) { - return Vector<GeoPoint>(nullptr, 0); - } - Int offset = static_cast<Int>(headers_[row_id] >> 16); - if (size < 0xFFFF) { - return Vector<GeoPoint>(&bodies_[offset], size); - } else { - // The size of a long vector is stored in front of the body. - std::memcpy(&size, &bodies_[offset], sizeof(Int)); - return Vector<GeoPoint>(&bodies_[offset + 1], size); - } - } - - // Read values. - void read(ArrayCRef<Record> records, - ArrayRef<Vector<GeoPoint>> values) const { - for (Int i = 0; i < records.size(); ++i) { - values.set(i, get(records.get_row_id(i))); - } - } - - private: - Array<UInt> headers_; - Array<GeoPoint> bodies_; - - ColumnImpl(); -}; - -// TODO: Improve the implementation. -template <> -class ColumnImpl<Vector<Text>> : public impl::ColumnBase { - public: - // -- Public API -- - - bool set(Error *error, Int row_id, const Datum &datum); - bool get(Error *error, Int row_id, Datum *datum) const; - - // -- Internal API -- - - // Create a new column. - // - // Returns a pointer to the column on success. - // On failure, returns nullptr and stores error information into "*error" if - // "error" != nullptr. - static unique_ptr<ColumnImpl> create(Error *error, - impl::Table *table, - const StringCRef &name, - const ColumnOptions &options); - - ~ColumnImpl(); - - bool set_default_value(Error *error, Int row_id); - void unset(Int row_id); - - // Return a value identified by "row_id". - // - // Assumes that "row_id" is valid. Otherwise, the result is undefined. - Vector<Text> get(Int row_id) const { - return Vector<Text>(&text_headers_[headers_[row_id].offset], - bodies_.data(), headers_[row_id].size); - } - - // Read values. - void read(ArrayCRef<Record> records, ArrayRef<Vector<Text>> values) const { - for (Int i = 0; i < records.size(); ++i) { - values.set(i, get(records.get_row_id(i))); - } - } - - private: - struct Header { - Int offset; - Int size; - }; - Array<Header> headers_; - Array<Header> text_headers_; - Array<char> bodies_; - - ColumnImpl(); -}; - -} // namespace grnxx - -#endif // GRNXX_COLUMN_IMPL_HPP Modified: lib/grnxx/expression.cpp (+7 -7) =================================================================== --- lib/grnxx/expression.cpp 2014-10-07 11:30:11 +0900 (46145b3) +++ lib/grnxx/expression.cpp 2014-10-07 13:33:14 +0900 (ed88cca) @@ -1,6 +1,6 @@ #include "grnxx/expression.hpp" -#include "grnxx/column_impl.hpp" +#include "grnxx/impl/column.hpp" #include "grnxx/table.hpp" #include <iostream> // For debugging. @@ -625,7 +625,7 @@ class ColumnNode : public TypedNode<T> { explicit ColumnNode(const Column *column) : TypedNode<Value>(), - column_(static_cast<const ColumnImpl<Value> *>(column)) {} + column_(static_cast<const impl::Column<Value> *>(column)) {} NodeType node_type() const { return COLUMN_NODE; @@ -642,7 +642,7 @@ class ColumnNode : public TypedNode<T> { } private: - const ColumnImpl<T> *column_; + const impl::Column<T> *column_; }; template <> @@ -660,7 +660,7 @@ class ColumnNode<Bool> : public TypedNode<Bool> { explicit ColumnNode(const Column *column) : TypedNode<Value>(), - column_(static_cast<const ColumnImpl<Value> *>(column)) {} + column_(static_cast<const impl::Column<Value> *>(column)) {} NodeType node_type() const { return COLUMN_NODE; @@ -677,7 +677,7 @@ class ColumnNode<Bool> : public TypedNode<Bool> { } private: - const ColumnImpl<Value> *column_; + const impl::Column<Value> *column_; }; bool ColumnNode<Bool>::filter(Error *, @@ -709,7 +709,7 @@ class ColumnNode<Float> : public TypedNode<Float> { explicit ColumnNode(const Column *column) : TypedNode<Value>(), - column_(static_cast<const ColumnImpl<Value> *>(column)) {} + column_(static_cast<const impl::Column<Value> *>(column)) {} NodeType node_type() const { return COLUMN_NODE; @@ -729,7 +729,7 @@ class ColumnNode<Float> : public TypedNode<Float> { } private: - const ColumnImpl<Value> *column_; + const impl::Column<Value> *column_; }; // -- OperatorNode -- Modified: lib/grnxx/impl/column.hpp (+10 -11) =================================================================== --- lib/grnxx/impl/column.hpp 2014-10-07 11:30:11 +0900 (16eb144) +++ lib/grnxx/impl/column.hpp 2014-10-07 13:33:14 +0900 (8ea542d) @@ -1,16 +1,15 @@ #ifndef GRNXX_IMPL_COLUMN_HPP #define GRNXX_IMPL_COLUMN_HPP -#include "grnxx/impl/column/column_base.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/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" #endif // GRNXX_IMPL_COLUMN_HPP Modified: lib/grnxx/impl/column/Makefile.am (+24 -2) =================================================================== --- lib/grnxx/impl/column/Makefile.am 2014-10-07 11:30:11 +0900 (8a5ffdc) +++ lib/grnxx/impl/column/Makefile.am 2014-10-07 13:33:14 +0900 (f97bf8f) @@ -9,8 +9,30 @@ lib_LTLIBRARIES = libgrnxx_impl_column.la libgrnxx_impl_column_la_LDFLAGS = @AM_LTLDFLAGS@ libgrnxx_impl_column_la_SOURCES = \ - column_base.cpp + column.cpp \ + column_base.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 libgrnxx_impl_column_includedir = ${includedir}/grnxx/impl/column libgrnxx_impl_column_include_HEADERS = \ - column_base.hpp + 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 Added: lib/grnxx/impl/column/column.cpp (+114 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column.cpp 2014-10-07 13:33:14 +0900 (993d55b) @@ -0,0 +1,114 @@ +#include "grnxx/impl/column/column.hpp" + +#include "grnxx/cursor.hpp" +#include "grnxx/impl/db.hpp" +#include "grnxx/impl/table.hpp" +#include "grnxx/index.hpp" + +#include <set> + +namespace grnxx { +namespace impl { + +template <typename T> +bool Column<T>::set(Error *error, Int row_id, const Datum &datum) { + if (datum.type() != TypeTraits<T>::data_type()) { + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); + return false; + } + if (!table_->test_row(error, row_id)) { + return false; + } + // Note that a Bool object does not have its own address. + T old_value = get(row_id); + T new_value; + datum.force(&new_value); + // TODO: Note that NaN != NaN. + if (new_value != old_value) { + for (Int i = 0; i < num_indexes(); ++i) { + if (!indexes_[i]->insert(error, row_id, datum)) { + for (Int j = 0; j < i; ++i) { + indexes_[j]->remove(nullptr, row_id, datum); + } + return false; + } + } + for (Int i = 0; i < num_indexes(); ++i) { + indexes_[i]->remove(nullptr, row_id, old_value); + } + } + values_.set(row_id, new_value); + return true; +} + +template <typename T> +bool Column<T>::get(Error *error, Int row_id, Datum *datum) const { + if (!table_->test_row(error, row_id)) { + return false; + } + *datum = values_[row_id]; + return true; +} + +template <typename T> +unique_ptr<Column<T>> Column<T>::create(Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options) { + unique_ptr<Column> column(new (nothrow) Column); + if (!column) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return nullptr; + } + if (!column->initialize_base(error, table, name, + TypeTraits<T>::data_type(), options)) { + return nullptr; + } + if (!column->values_.resize(error, table->max_row_id() + 1, + TypeTraits<T>::default_value())) { + return nullptr; + } + return column; +} + +template <typename T> +Column<T>::~Column() {} + +template <typename T> +bool Column<T>::set_default_value(Error *error, Int row_id) { + if (row_id >= values_.size()) { + if (!values_.resize(error, row_id + 1, TypeTraits<T>::default_value())) { + return false; + } + } + T value = TypeTraits<T>::default_value(); + for (Int i = 0; i < num_indexes(); ++i) { + if (!indexes_[i]->insert(error, row_id, value)) { + for (Int j = 0; j < i; ++j) { + indexes_[j]->remove(nullptr, row_id, value); + } + return false; + } + } + values_.set(row_id, value); + return true; +} + +template <typename T> +void Column<T>::unset(Int row_id) { + for (Int i = 0; i < num_indexes(); ++i) { + indexes_[i]->remove(nullptr, row_id, get(row_id)); + } + values_.set(row_id, TypeTraits<T>::default_value()); +} + +template <typename T> +Column<T>::Column() : ColumnBase(), values_() {} + +template class Column<Bool>; +template class Column<Float>; +template class Column<GeoPoint>; +template class Column<Vector<Bool>>; + +} // namespace impl +} // namespace grnxx Added: lib/grnxx/impl/column/column.hpp (+61 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column.hpp 2014-10-07 13:33:14 +0900 (a440562) @@ -0,0 +1,61 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_HPP + +#include "grnxx/impl/column/column_base.hpp" + +namespace grnxx { +namespace impl { + +//template <typename T> class Column; + +template <typename T> +class Column : public ColumnBase { + public: + // -- Public API (grnxx/column.hpp) -- + + bool set(Error *error, Int row_id, const Datum &datum); + bool get(Error *error, Int row_id, Datum *datum) const; + + // -- Internal API (grnxx/impl/column/column_base.hpp) -- + + ~Column(); + + bool set_default_value(Error *error, Int row_id); + void unset(Int row_id); + + // -- Internal API -- + + // Create a new column. + // + // Returns a pointer to the column on success. + // On failure, returns nullptr and stores error information into "*error" if + // "error" != nullptr. + static unique_ptr<Column> create(Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options); + + // Return a value identified by "row_id". + // + // Assumes that "row_id" is valid. Otherwise, the result is undefined. + T get(Int row_id) const { + return values_[row_id]; + } + + // Read values. + void read(ArrayCRef<Record> records, ArrayRef<T> values) const { + for (Int i = 0; i < records.size(); ++i) { + values.set(i, get(records.get_row_id(i))); + } + } + + private: + Array<T> values_; + + Column(); +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_HPP Modified: lib/grnxx/impl/column/column_base.cpp (+51 -42) =================================================================== --- lib/grnxx/impl/column/column_base.cpp 2014-10-07 11:30:11 +0900 (2f11e61) +++ lib/grnxx/impl/column/column_base.cpp 2014-10-07 13:33:14 +0900 (6f2817e) @@ -1,7 +1,16 @@ #include "grnxx/impl/column/column_base.hpp" -#include "grnxx/column_impl.hpp" -#include "grnxx/cursor.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" @@ -140,9 +149,6 @@ Int ColumnBase::find_one(const Datum &) const { return NULL_ROW_ID; } -void ColumnBase::clear_references(Int) { -} - unique_ptr<ColumnBase> ColumnBase::create(Error *error, Table *table, const StringCRef &name, @@ -150,34 +156,34 @@ unique_ptr<ColumnBase> ColumnBase::create(Error *error, const ColumnOptions &options) { switch (data_type) { case BOOL_DATA: { - return ColumnImpl<Bool>::create(error, table, name, options); + return impl::Column<Bool>::create(error, table, name, options); } case INT_DATA: { - return ColumnImpl<Int>::create(error, table, name, options); + return impl::Column<Int>::create(error, table, name, options); } case FLOAT_DATA: { - return ColumnImpl<Float>::create(error, table, name, options); + return impl::Column<Float>::create(error, table, name, options); } case GEO_POINT_DATA: { - return ColumnImpl<GeoPoint>::create(error, table, name, options); + return impl::Column<GeoPoint>::create(error, table, name, options); } case TEXT_DATA: { - return ColumnImpl<Text>::create(error, table, name, options); + return impl::Column<Text>::create(error, table, name, options); } case BOOL_VECTOR_DATA: { - return ColumnImpl<Vector<Bool>>::create(error, table, name, options); + return impl::Column<Vector<Bool>>::create(error, table, name, options); } case INT_VECTOR_DATA: { - return ColumnImpl<Vector<Int>>::create(error, table, name, options); + return impl::Column<Vector<Int>>::create(error, table, name, options); } case FLOAT_VECTOR_DATA: { - return ColumnImpl<Vector<Float>>::create(error, table, name, options); + return impl::Column<Vector<Float>>::create(error, table, name, options); } case GEO_POINT_VECTOR_DATA: { - return ColumnImpl<Vector<GeoPoint>>::create(error, table, name, options); + return impl::Column<Vector<GeoPoint>>::create(error, table, name, options); } case TEXT_VECTOR_DATA: { - return ColumnImpl<Vector<Text>>::create(error, table, name, options); + return impl::Column<Vector<Text>>::create(error, table, name, options); } default: { // TODO: Other data types are not supported yet. @@ -187,12 +193,40 @@ unique_ptr<ColumnBase> ColumnBase::create(Error *error, } } +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_ = static_cast<impl::Table *>(table); + table_ = table; if (!name_.assign(error, name)) { return false; } @@ -203,37 +237,12 @@ bool ColumnBase::initialize_base(Error *error, if (!ref_table) { return false; } - ref_table_ = static_cast<impl::Table *>(ref_table); + ref_table_ = ref_table; } } return true; } -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_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; -} - -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; -} - Index *ColumnBase::find_index_with_id(Error *error, const StringCRef &name, Int *index_id) const { Modified: lib/grnxx/impl/column/column_base.hpp (+14 -28) =================================================================== --- lib/grnxx/impl/column/column_base.hpp 2014-10-07 11:30:11 +0900 (db2ca3d) +++ lib/grnxx/impl/column/column_base.hpp 2014-10-07 13:33:14 +0900 (ad32fdb) @@ -53,6 +53,12 @@ class ColumnBase : public ColumnInterface { } 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. @@ -77,34 +83,6 @@ class ColumnBase : public ColumnInterface { return ref_table_; } - // 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); - - // 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; - - // Check if "datum" exists in the column or not. - // - // If exists, returns true. - // Otherwise, returns false. - virtual bool contains(const Datum &datum) const; - - // Find "datum" in the column. - // - // If found, returns the row ID of the matched value. - // Otherwise, returns NULL_ROW_ID. - virtual Int find_one(const Datum &datum) const; - // Change the column name. // // On success, returns true. @@ -116,8 +94,16 @@ class ColumnBase : public ColumnInterface { 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. Added: lib/grnxx/impl/column/column_bool.hpp (+14 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_bool.hpp 2014-10-07 13:33:14 +0900 (0a36846) @@ -0,0 +1,14 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_BOOL_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_BOOL_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +// TODO + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_BOOL_HPP Added: lib/grnxx/impl/column/column_float.hpp (+14 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_float.hpp 2014-10-07 13:33:14 +0900 (9fb732c) @@ -0,0 +1,14 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_FLOAT_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_FLOAT_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +// TODO + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_FLOAT_HPP Added: lib/grnxx/impl/column/column_geo_point.hpp (+14 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_geo_point.hpp 2014-10-07 13:33:14 +0900 (98d7a58) @@ -0,0 +1,14 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_GEO_POINT_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_GEO_POINT_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +// TODO + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_GEO_POINT_HPP Added: lib/grnxx/impl/column/column_int.cpp (+279 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_int.cpp 2014-10-07 13:33:14 +0900 (bb80bfa) @@ -0,0 +1,279 @@ +#include "grnxx/impl/column/column_int.hpp" + +#include "grnxx/cursor.hpp" +#include "grnxx/impl/db.hpp" +#include "grnxx/impl/table.hpp" +#include "grnxx/index.hpp" + +#include <unordered_set> + +namespace grnxx { +namespace impl { + +bool Column<Int>::set(Error *error, Int row_id, const Datum &datum) { + if (datum.type() != INT_DATA) { + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); + return false; + } + if (!table_->test_row(error, row_id)) { + return false; + } + if (ref_table_) { + if (!ref_table_->test_row(error, datum.force_int())) { + return false; + } + } + Int old_value = get(row_id); + Int new_value = datum.force_int(); + if (new_value != old_value) { + if (has_key_attribute_ && contains(datum)) { + GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate"); + return false; + } + for (Int i = 0; i < num_indexes(); ++i) { + if (!indexes_[i]->insert(error, row_id, datum)) { + for (Int j = 0; j < i; ++i) { + indexes_[j]->remove(nullptr, row_id, datum); + } + return false; + } + } + for (Int i = 0; i < num_indexes(); ++i) { + indexes_[i]->remove(nullptr, row_id, old_value); + } + } + values_.set(row_id, new_value); + return true; +} + +bool Column<Int>::get(Error *error, Int row_id, Datum *datum) const { + if (!table_->test_row(error, row_id)) { + return false; + } + *datum = values_[row_id]; + return true; +} + +unique_ptr<Column<Int>> Column<Int>::create( + Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options) { + unique_ptr<Column> column(new (nothrow) Column); + if (!column) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return nullptr; + } + if (!column->initialize_base(error, table, name, INT_DATA, options)) { + return nullptr; + } + if (!column->values_.resize(error, table->max_row_id() + 1, + TypeTraits<Int>::default_value())) { + return nullptr; + } + if (column->ref_table()) { + if (!column->ref_table_->append_referrer_column(error, column.get())) { + return nullptr; + } + } + return column; +} + +Column<Int>::~Column() {} + +bool Column<Int>::set_key_attribute(Error *error) { + if (has_key_attribute_) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, + "This column is a key column"); + return false; + } + // TODO: An index should be used if possible. + try { + std::unordered_set<Int> set; + // TODO: Functor-based inline callback may be better in this case, + // because it does not require memory allocation. + auto cursor = table_->create_cursor(nullptr); + if (!cursor) { + return false; + } + Array<Record> records; + for ( ; ; ) { + auto result = cursor->read(nullptr, 1024, &records); + if (!result.is_ok) { + return false; + } else { + break; + } + for (Int i = 0; i < result.count; ++i) { + if (!set.insert(values_[records.get_row_id(i)]).second) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, "Key duplicate"); + return false; + } + } + records.clear(); + } + } catch (...) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return false; + } + has_key_attribute_ = true; + return true; +} + +bool Column<Int>::unset_key_attribute(Error *error) { + if (!has_key_attribute_) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, + "This column is not a key column"); + return false; + } + has_key_attribute_ = false; + return true; +} + +bool Column<Int>::set_initial_key(Error *error, + Int row_id, + const Datum &key) { + if (!has_key_attribute_) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, + "This column is not a key column"); + return false; + } + if (has_key_attribute_ && contains(key)) { + GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate"); + return false; + } + if (row_id >= values_.size()) { + if (!values_.resize(error, row_id + 1, TypeTraits<Int>::default_value())) { + return false; + } + } + Int value = key.force_int(); + for (Int i = 0; i < num_indexes(); ++i) { + if (!indexes_[i]->insert(error, row_id, value)) { + for (Int j = 0; j < i; ++j) { + indexes_[j]->remove(nullptr, row_id, value); + } + return false; + } + } + values_.set(row_id, value); + return true; +} + +bool Column<Int>::set_default_value(Error *error, Int row_id) { + if (has_key_attribute_) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, + "This column is a key column"); + return false; + } + if (row_id >= values_.size()) { + if (!values_.resize(error, row_id + 1, TypeTraits<Int>::default_value())) { + return false; + } + } + Int value = TypeTraits<Int>::default_value(); + for (Int i = 0; i < num_indexes(); ++i) { + if (!indexes_[i]->insert(error, row_id, value)) { + for (Int j = 0; j < i; ++j) { + indexes_[j]->remove(nullptr, row_id, value); + } + return false; + } + } + values_.set(row_id, value); + return true; +} + +void Column<Int>::unset(Int row_id) { + for (Int i = 0; i < num_indexes(); ++i) { + indexes_[i]->remove(nullptr, row_id, get(row_id)); + } + values_.set(row_id, TypeTraits<Int>::default_value()); +} + +Int Column<Int>::find_one(const Datum &datum) const { + // TODO: Cursor should not be used because it takes time. + // Also, cursor operations can fail due to memory allocation. + Int value = datum.force_int(); + if (indexes_.size() != 0) { + return indexes_[0]->find_one(datum); + } else { + // TODO: A full scan takes time. + // An index should be required for a key column. + + // TODO: Functor-based inline callback may be better in this case, + // because it does not require memory allocation. + + // Scan the column to find "value". + auto cursor = table_->create_cursor(nullptr); + if (!cursor) { + return NULL_ROW_ID; + } + Array<Record> records; + for ( ; ; ) { + auto result = cursor->read(nullptr, 1024, &records); + if (!result.is_ok || result.count == 0) { + return NULL_ROW_ID; + } + for (Int i = 0; i < result.count; ++i) { + if (values_[records.get_row_id(i)] == value) { + return records.get_row_id(i); + } + } + records.clear(); + } + } + return NULL_ROW_ID; +} + +void Column<Int>::clear_references(Int row_id) { + // TODO: Cursor should not be used to avoid errors. + if (indexes_.size() != 0) { + auto cursor = indexes_[0]->find(nullptr, Int(0)); + if (!cursor) { + // Error. + return; + } + Array<Record> records; + for ( ; ; ) { + auto result = cursor->read(nullptr, 1024, &records); + if (!result.is_ok) { + // Error. + return; + } else if (result.count == 0) { + return; + } + for (Int i = 0; i < records.size(); ++i) { + set(nullptr, row_id, NULL_ROW_ID); + } + records.clear(); + } + } else { + auto cursor = table_->create_cursor(nullptr); + if (!cursor) { + // Error. + return; + } + Array<Record> records; + for ( ; ; ) { + auto result = cursor->read(nullptr, 1024, &records); + if (!result.is_ok) { + // Error. + return; + } else if (result.count == 0) { + return; + } + for (Int i = 0; i < records.size(); ++i) { + if (values_[records.get_row_id(i)] == row_id) { + values_[records.get_row_id(i)] = NULL_ROW_ID; + } + } + records.clear(); + } + } +} + +Column<Int>::Column() : ColumnBase(), values_() {} + +} // namespace impl +} // namespace grnxx Added: lib/grnxx/impl/column/column_int.hpp (+65 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_int.hpp 2014-10-07 13:33:14 +0900 (7ca0b23) @@ -0,0 +1,65 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_INT_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_INT_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +template <> +class Column<Int> : public ColumnBase { + public: + // -- Public API -- + + bool set(Error *error, Int row_id, const Datum &datum); + bool get(Error *error, Int row_id, Datum *datum) const; + + // -- Internal API -- + + // Create a new column. + // + // Returns a pointer to the column on success. + // On failure, returns nullptr and stores error information into "*error" if + // "error" != nullptr. + static unique_ptr<Column> create(Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options); + + ~Column(); + + bool set_key_attribute(Error *error); + bool unset_key_attribute(Error *error); + + bool set_initial_key(Error *error, Int row_id, const Datum &key); + bool set_default_value(Error *error, Int row_id); + void unset(Int row_id); + + Int find_one(const Datum &datum) const; + + void clear_references(Int row_id); + + // Return a value identified by "row_id". + // + // Assumes that "row_id" is valid. Otherwise, the result is undefined. + Int get(Int row_id) const { + return values_[row_id]; + } + + // Read values. + void read(ArrayCRef<Record> records, ArrayRef<Int> values) const { + for (Int i = 0; i < records.size(); ++i) { + values.set(i, get(records.get_row_id(i))); + } + } + + private: + Array<Int> values_; + + Column(); +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_INT_HPP Added: lib/grnxx/impl/column/column_text.cpp (+268 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_text.cpp 2014-10-07 13:33:14 +0900 (2db612a) @@ -0,0 +1,268 @@ +#include "grnxx/impl/column/column_text.hpp" + +#include "grnxx/cursor.hpp" +#include "grnxx/impl/db.hpp" +#include "grnxx/impl/table.hpp" +#include "grnxx/index.hpp" + +#include <set> + +namespace grnxx { +namespace impl { + +bool Column<Text>::set(Error *error, Int row_id, const Datum &datum) { + if (datum.type() != TEXT_DATA) { + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); + return false; + } + if (!table_->test_row(error, row_id)) { + return false; + } + Text old_value = get(row_id); + Text new_value = datum.force_text(); + if (new_value != old_value) { + if (has_key_attribute_ && contains(datum)) { + GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate"); + return false; + } + for (Int i = 0; i < num_indexes(); ++i) { + if (!indexes_[i]->insert(error, row_id, datum)) { + for (Int j = 0; j < i; ++i) { + indexes_[j]->remove(nullptr, row_id, datum); + } + return false; + } + } + Int offset = bodies_.size(); + UInt new_header; + if (new_value.size() < 0xFFFF) { + if (!bodies_.resize(error, offset + new_value.size())) { + return false; + } + std::memcpy(&bodies_[offset], new_value.data(), new_value.size()); + new_header = (offset << 16) | new_value.size(); + } else { + // The size of a long text is stored in front of the body. + if ((offset % sizeof(Int)) != 0) { + offset += sizeof(Int) - (offset % sizeof(Int)); + } + if (!bodies_.resize(error, offset + sizeof(Int) + new_value.size())) { + return false; + } + *reinterpret_cast<Int *>(&bodies_[offset]) = new_value.size(); + std::memcpy(&bodies_[offset + sizeof(Int)], + new_value.data(), new_value.size()); + new_header = (offset << 16) | 0xFFFF; + } + for (Int i = 0; i < num_indexes(); ++i) { + indexes_[i]->remove(nullptr, row_id, old_value); + } + headers_[row_id] = new_header; + } + return true; +} + +bool Column<Text>::get(Error *error, Int row_id, Datum *datum) const { + if (!table_->test_row(error, row_id)) { + return false; + } + *datum = get(row_id); + return true; +} + +unique_ptr<Column<Text>> Column<Text>::create( + Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options) { + unique_ptr<Column> column(new (nothrow) Column); + if (!column) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return nullptr; + } + if (!column->initialize_base(error, table, name, TEXT_DATA, options)) { + return nullptr; + } + if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) { + return nullptr; + } + return column; +} + +Column<Text>::~Column() {} + +bool Column<Text>::set_key_attribute(Error *error) { + if (has_key_attribute_) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, + "This column is a key column"); + return false; + } + // TODO: An index should be used if possible. + try { + std::set<Text> set; + // TODO: Functor-based inline callback may be better in this case, + // because it does not require memory allocation. + auto cursor = table_->create_cursor(nullptr); + if (!cursor) { + return false; + } + Array<Record> records; + for ( ; ; ) { + auto result = cursor->read(nullptr, 1024, &records); + if (!result.is_ok) { + return false; + } else { + break; + } + for (Int i = 0; i < result.count; ++i) { + if (!set.insert(get(records.get_row_id(i))).second) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, "Key duplicate"); + return false; + } + } + records.clear(); + } + } catch (...) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return false; + } + has_key_attribute_ = true; + return true; +} + +bool Column<Text>::unset_key_attribute(Error *error) { + if (!has_key_attribute_) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, + "This column is not a key column"); + return false; + } + has_key_attribute_ = false; + return true; +} + +bool Column<Text>::set_initial_key(Error *error, + Int row_id, + const Datum &key) { + if (!has_key_attribute_) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, + "This column is not a key column"); + return false; + } + if (has_key_attribute_ && contains(key)) { + GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate"); + return false; + } + if (row_id >= headers_.size()) { + if (!headers_.resize(error, row_id + 1, 0)) { + return false; + } + } + Text value = key.force_text(); + for (Int i = 0; i < num_indexes(); ++i) { + if (!indexes_[i]->insert(error, row_id, value)) { + for (Int j = 0; j < i; ++j) { + indexes_[j]->remove(nullptr, row_id, value); + } + return false; + } + } + Int offset = bodies_.size(); + UInt header; + if (value.size() < 0xFFFF) { + if (!bodies_.resize(error, offset + value.size())) { + return false; + } + std::memcpy(&bodies_[offset], value.data(), value.size()); + header = (offset << 16) | value.size(); + } else { + // The size of a long text is stored in front of the body. + if ((offset % sizeof(Int)) != 0) { + offset += sizeof(Int) - (offset % sizeof(Int)); + } + if (!bodies_.resize(error, offset + sizeof(Int) + value.size())) { + return false; + } + *reinterpret_cast<Int *>(&bodies_[offset]) = value.size(); + std::memcpy(&bodies_[offset + sizeof(Int)], value.data(), value.size()); + header = (offset << 16) | 0xFFFF; + } + headers_[row_id] = header; + return true; +} + +bool Column<Text>::set_default_value(Error *error, Int row_id) { + if (has_key_attribute_) { + GRNXX_ERROR_SET(error, INVALID_OPERATION, + "This column is a key column"); + return false; + } + if (row_id >= headers_.size()) { + if (!headers_.resize(error, row_id + 1)) { + return false; + } + } + Text value = TypeTraits<Text>::default_value(); + for (Int i = 0; i < num_indexes(); ++i) { + if (!indexes_[i]->insert(error, row_id, value)) { + for (Int j = 0; j < i; ++j) { + indexes_[j]->remove(nullptr, row_id, value); + } + return false; + } + } + headers_[row_id] = 0; + return true; +} + +void Column<Text>::unset(Int row_id) { + for (Int i = 0; i < num_indexes(); ++i) { + indexes_[i]->remove(nullptr, row_id, get(row_id)); + } + headers_[row_id] = 0; +} + +Int Column<Text>::find_one(const Datum &datum) const { + // TODO: Cursor should not be used because it takes time. + // Also, cursor operations can fail due to memory allocation. + Text value = datum.force_text(); + if (indexes_.size() != 0) { + auto cursor = indexes_[0]->find(nullptr, value); + Array<Record> records; + auto result = cursor->read(nullptr, 1, &records); + if (!result.is_ok || (result.count == 0)) { + return NULL_ROW_ID; + } + return true; + } else { + // TODO: A full scan takes time. + // An index should be required for a key column. + + // TODO: Functor-based inline callback may be better in this case, + // because it does not require memory allocation. + + // Scan the column to find "value". + auto cursor = table_->create_cursor(nullptr); + if (!cursor) { + return NULL_ROW_ID; + } + Array<Record> records; + for ( ; ; ) { + auto result = cursor->read(nullptr, 1024, &records); + if (!result.is_ok || result.count == 0) { + return NULL_ROW_ID; + } + for (Int i = 0; i < result.count; ++i) { + if (get(records.get_row_id(i)) == value) { + return records.get_row_id(i); + } + } + records.clear(); + } + } + return NULL_ROW_ID; +} + +Column<Text>::Column() : ColumnBase(), headers_(), bodies_() {} + +} // namespace impl +} // namespace grnxx Added: lib/grnxx/impl/column/column_text.hpp (+74 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_text.hpp 2014-10-07 13:33:14 +0900 (493a5ed) @@ -0,0 +1,74 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_TEXT_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_TEXT_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +template <> +class Column<Text> : public impl::ColumnBase { + public: + // -- Public API -- + + bool set(Error *error, Int row_id, const Datum &datum); + bool get(Error *error, Int row_id, Datum *datum) const; + + // -- Internal API -- + + // Create a new column. + // + // Returns a pointer to the column on success. + // On failure, returns nullptr and stores error information into "*error" if + // "error" != nullptr. + static unique_ptr<Column> create(Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options); + + ~Column(); + + bool set_key_attribute(Error *error); + bool unset_key_attribute(Error *error); + + bool set_initial_key(Error *error, Int row_id, const Datum &key); + bool set_default_value(Error *error, Int row_id); + void unset(Int row_id); + Int find_one(const Datum &datum) const; + + // Return a value identified by "row_id". + // + // Assumes that "row_id" is valid. Otherwise, the result is undefined. + Text get(Int row_id) const { + Int size = static_cast<Int>(headers_[row_id] & 0xFFFF); + if (size == 0) { + return Text("", 0); + } + Int offset = static_cast<Int>(headers_[row_id] >> 16); + if (size < 0xFFFF) { + return Text(&bodies_[offset], size); + } else { + // The size of a long text is stored in front of the body. + size = *reinterpret_cast<const Int *>(&bodies_[offset]); + return StringCRef(&bodies_[offset + sizeof(Int)], size); + } + } + + // Read values. + void read(ArrayCRef<Record> records, ArrayRef<Text> values) const { + for (Int i = 0; i < records.size(); ++i) { + values.set(i, get(records.get_row_id(i))); + } + } + + private: + Array<UInt> headers_; + Array<char> bodies_; + + Column(); +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_TEXT_HPP Added: lib/grnxx/impl/column/column_vector_bool.hpp (+14 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_bool.hpp 2014-10-07 13:33:14 +0900 (94fbb93) @@ -0,0 +1,14 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_VECTOR_BOOL_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_VECTOR_BOOL_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +// TODO + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_VECTOR_BOOL_HPP Added: lib/grnxx/impl/column/column_vector_float.cpp (+98 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_float.cpp 2014-10-07 13:33:14 +0900 (ca6b184) @@ -0,0 +1,98 @@ +#include "grnxx/impl/column/column_vector_float.hpp" + +#include "grnxx/cursor.hpp" +#include "grnxx/impl/db.hpp" +#include "grnxx/impl/table.hpp" + +namespace grnxx { +namespace impl { + + +bool Column<Vector<Float>>::set(Error *error, Int row_id, const Datum &datum) { + if (datum.type() != FLOAT_VECTOR_DATA) { + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); + return false; + } + if (!table_->test_row(error, row_id)) { + return false; + } + Vector<Float> value = datum.force_float_vector(); + if (value.size() == 0) { + headers_[row_id] = 0; + return true; + } + Int offset = bodies_.size(); + if (value.size() < 0xFFFF) { + if (!bodies_.resize(error, offset + value.size())) { + return false; + } + for (Int i = 0; i < value.size(); ++i) { + bodies_[offset + i] = value[i]; + } + headers_[row_id] = (offset << 16) | value.size(); + } else { + // The size of a long vector is stored in front of the body. + if (!bodies_.resize(error, offset + 1 + value.size())) { + return false; + } + Int size_for_copy = value.size(); + std::memcpy(&bodies_[offset], &size_for_copy, sizeof(Int)); + for (Int i = 0; i < value.size(); ++i) { + bodies_[offset + 1 + i] = value[i]; + } + headers_[row_id] = (offset << 16) | 0xFFFF; + } + return true; +} + +bool Column<Vector<Float>>::get(Error *error, Int row_id, Datum *datum) const { + if (!table_->test_row(error, row_id)) { + return false; + } + *datum = get(row_id); + return true; +} + +unique_ptr<Column<Vector<Float>>> Column<Vector<Float>>::create( + Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options) { + unique_ptr<Column> column(new (nothrow) Column); + if (!column) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return nullptr; + } + if (!column->initialize_base(error, table, name, + FLOAT_VECTOR_DATA, options)) { + return nullptr; + } + if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) { + return nullptr; + } + return column; +} + +Column<Vector<Float>>::~Column() {} + +bool Column<Vector<Float>>::set_default_value(Error *error, Int row_id) { + if (row_id >= headers_.size()) { + if (!headers_.resize(error, row_id + 1)) { + return false; + } + } + headers_[row_id] = 0; + return true; +} + +void Column<Vector<Float>>::unset(Int row_id) { + headers_[row_id] = 0; +} + +Column<Vector<Float>>::Column() + : ColumnBase(), + headers_(), + bodies_() {} + +} // namespace impl +} // namespace grnxx Added: lib/grnxx/impl/column/column_vector_float.hpp (+69 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_float.hpp 2014-10-07 13:33:14 +0900 (1e76db5) @@ -0,0 +1,69 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_VECTOR_FLOAT_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_VECTOR_FLOAT_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +template <> +class Column<Vector<Float>> : public ColumnBase { + public: + // -- Public API -- + + bool set(Error *error, Int row_id, const Datum &datum); + bool get(Error *error, Int row_id, Datum *datum) const; + + // -- Internal API -- + + // Create a new column. + // + // Returns a pointer to the column on success. + // On failure, returns nullptr and stores error information into "*error" if + // "error" != nullptr. + static unique_ptr<Column> create(Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options); + + ~Column(); + + bool set_default_value(Error *error, Int row_id); + void unset(Int row_id); + + // Return a value identified by "row_id". + // + // Assumes that "row_id" is valid. Otherwise, the result is undefined. + Vector<Float> get(Int row_id) const { + Int size = static_cast<Int>(headers_[row_id] & 0xFFFF); + if (size == 0) { + return Vector<Float>(nullptr, 0); + } + Int offset = static_cast<Int>(headers_[row_id] >> 16); + if (size < 0xFFFF) { + return Vector<Float>(&bodies_[offset], size); + } else { + // The size of a long vector is stored in front of the body. + std::memcpy(&size, &bodies_[offset], sizeof(Int)); + return Vector<Float>(&bodies_[offset + 1], size); + } + } + + // Read values. + void read(ArrayCRef<Record> records, ArrayRef<Vector<Float>> values) const { + for (Int i = 0; i < records.size(); ++i) { + values.set(i, get(records.get_row_id(i))); + } + } + + private: + Array<UInt> headers_; + Array<Float> bodies_; + + Column(); +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_VECTOR_FLOAT_HPP Added: lib/grnxx/impl/column/column_vector_geo_point.cpp (+100 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_geo_point.cpp 2014-10-07 13:33:14 +0900 (3eaceaa) @@ -0,0 +1,100 @@ +#include "grnxx/impl/column/column_vector_geo_point.hpp" + +#include "grnxx/cursor.hpp" +#include "grnxx/impl/db.hpp" +#include "grnxx/impl/table.hpp" + +namespace grnxx { +namespace impl { + +bool Column<Vector<GeoPoint>>::set(Error *error, Int row_id, + const Datum &datum) { + if (datum.type() != GEO_POINT_VECTOR_DATA) { + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); + return false; + } + if (!table_->test_row(error, row_id)) { + return false; + } + Vector<GeoPoint> value = datum.force_geo_point_vector(); + if (value.size() == 0) { + headers_[row_id] = 0; + return true; + } + Int offset = bodies_.size(); + if (value.size() < 0xFFFF) { + if (!bodies_.resize(error, offset + value.size())) { + return false; + } + for (Int i = 0; i < value.size(); ++i) { + bodies_[offset + i] = value[i]; + } + headers_[row_id] = (offset << 16) | value.size(); + } else { + // The size of a long vector is stored in front of the body. + if (!bodies_.resize(error, offset + 1 + value.size())) { + return false; + } + Int size_for_copy = value.size(); + std::memcpy(&bodies_[offset], &size_for_copy, sizeof(Int)); + for (Int i = 0; i < value.size(); ++i) { + bodies_[offset + 1 + i] = value[i]; + } + headers_[row_id] = (offset << 16) | 0xFFFF; + } + return true; +} + +bool Column<Vector<GeoPoint>>::get(Error *error, Int row_id, + Datum *datum) const { + if (!table_->test_row(error, row_id)) { + return false; + } + *datum = get(row_id); + return true; +} + +unique_ptr<Column<Vector<GeoPoint>>> Column<Vector<GeoPoint>>::create( + Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options) { + unique_ptr<Column> column(new (nothrow) Column); + if (!column) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return nullptr; + } + if (!column->initialize_base(error, table, name, + GEO_POINT_VECTOR_DATA, options)) { + return nullptr; + } + if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) { + return nullptr; + } + return column; +} + +Column<Vector<GeoPoint>>::~Column() {} + +bool Column<Vector<GeoPoint>>::set_default_value(Error *error, + Int row_id) { + if (row_id >= headers_.size()) { + if (!headers_.resize(error, row_id + 1)) { + return false; + } + } + headers_[row_id] = 0; + return true; +} + +void Column<Vector<GeoPoint>>::unset(Int row_id) { + headers_[row_id] = 0; +} + +Column<Vector<GeoPoint>>::Column() + : ColumnBase(), + headers_(), + bodies_() {} + +} // namespace impl +} // namespace grnxx Added: lib/grnxx/impl/column/column_vector_geo_point.hpp (+71 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_geo_point.hpp 2014-10-07 13:33:14 +0900 (3911e4d) @@ -0,0 +1,71 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_VECTOR_GEO_POINT_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_VECTOR_GEO_POINT_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +// TODO +template <> +class Column<Vector<GeoPoint>> : public ColumnBase { + public: + // -- Public API -- + + bool set(Error *error, Int row_id, const Datum &datum); + bool get(Error *error, Int row_id, Datum *datum) const; + + // -- Internal API -- + + // Create a new column. + // + // Returns a pointer to the column on success. + // On failure, returns nullptr and stores error information into "*error" if + // "error" != nullptr. + static unique_ptr<Column> create(Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options); + + ~Column(); + + bool set_default_value(Error *error, Int row_id); + void unset(Int row_id); + + // Return a value identified by "row_id". + // + // Assumes that "row_id" is valid. Otherwise, the result is undefined. + Vector<GeoPoint> get(Int row_id) const { + Int size = static_cast<Int>(headers_[row_id] & 0xFFFF); + if (size == 0) { + return Vector<GeoPoint>(nullptr, 0); + } + Int offset = static_cast<Int>(headers_[row_id] >> 16); + if (size < 0xFFFF) { + return Vector<GeoPoint>(&bodies_[offset], size); + } else { + // The size of a long vector is stored in front of the body. + std::memcpy(&size, &bodies_[offset], sizeof(Int)); + return Vector<GeoPoint>(&bodies_[offset + 1], size); + } + } + + // Read values. + void read(ArrayCRef<Record> records, + ArrayRef<Vector<GeoPoint>> values) const { + for (Int i = 0; i < records.size(); ++i) { + values.set(i, get(records.get_row_id(i))); + } + } + + private: + Array<UInt> headers_; + Array<GeoPoint> bodies_; + + Column(); +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_VECTOR_GEO_POINT_HPP Added: lib/grnxx/impl/column/column_vector_int.cpp (+152 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_int.cpp 2014-10-07 13:33:14 +0900 (c743c08) @@ -0,0 +1,152 @@ +#include "grnxx/impl/column/column_vector_int.hpp" + +#include "grnxx/cursor.hpp" +#include "grnxx/impl/db.hpp" +#include "grnxx/impl/table.hpp" + +namespace grnxx { +namespace impl { + +bool Column<Vector<Int>>::set(Error *error, Int row_id, + const Datum &datum) { + if (datum.type() != INT_VECTOR_DATA) { + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); + return false; + } + if (!table_->test_row(error, row_id)) { + return false; + } + Vector<Int> value = datum.force_int_vector(); + if (value.size() == 0) { + headers_[row_id] = 0; + return true; + } + if (ref_table_) { + for (Int i = 0; i < value.size(); ++i) { + if (!ref_table_->test_row(error, value[i])) { + return false; + } + } + } + Int offset = bodies_.size(); + if (value.size() < 0xFFFF) { + if (!bodies_.resize(error, offset + value.size())) { + return false; + } + for (Int i = 0; i < value.size(); ++i) { + bodies_[offset + i] = value[i]; + } + headers_[row_id] = (offset << 16) | value.size(); + } else { + // The size of a long vector is stored in front of the body. + if (!bodies_.resize(error, offset + 1 + value.size())) { + return false; + } + bodies_[offset] = value.size(); + for (Int i = 0; i < value.size(); ++i) { + bodies_[offset + 1 + i] = value[i]; + } + headers_[row_id] = (offset << 16) | 0xFFFF; + } + return true; +} + +bool Column<Vector<Int>>::get(Error *error, Int row_id, Datum *datum) const { + if (!table_->test_row(error, row_id)) { + return false; + } + *datum = get(row_id); + return true; +} + +unique_ptr<Column<Vector<Int>>> Column<Vector<Int>>::create( + Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options) { + unique_ptr<Column> column(new (nothrow) Column); + if (!column) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return nullptr; + } + if (!column->initialize_base(error, table, name, INT_VECTOR_DATA, options)) { + return nullptr; + } + if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) { + return nullptr; + } + if (column->ref_table()) { + if (!column->ref_table_->append_referrer_column(error, column.get())) { + return nullptr; + } + } + return column; +} + +Column<Vector<Int>>::~Column() {} + +bool Column<Vector<Int>>::set_default_value(Error *error, Int row_id) { + if (row_id >= headers_.size()) { + if (!headers_.resize(error, row_id + 1)) { + return false; + } + } + headers_[row_id] = 0; + return true; +} + +void Column<Vector<Int>>::unset(Int row_id) { + headers_[row_id] = 0; +} + +void Column<Vector<Int>>::clear_references(Int row_id) { + auto cursor = table_->create_cursor(nullptr); + if (!cursor) { + // Error. + return; + } + Array<Record> records; + for ( ; ; ) { + auto result = cursor->read(nullptr, 1024, &records); + if (!result.is_ok) { + // Error. + return; + } else if (result.count == 0) { + return; + } + for (Int i = 0; i < records.size(); ++i) { + Int value_row_id = records.get_row_id(i); + Int value_size = static_cast<Int>(headers_[value_row_id] & 0xFFFF); + if (value_size == 0) { + continue; + } + Int value_offset = static_cast<Int>(headers_[value_row_id] >> 16); + if (value_size >= 0xFFFF) { + value_size = bodies_[value_offset]; + ++value_offset; + } + Int count = 0; + for (Int j = 0; j < value_size; ++j) { + if (bodies_[value_offset + j] != row_id) { + bodies_[value_offset + count] = bodies_[value_offset + j]; + ++count; + } + } + if (count < value_size) { + if (count == 0) { + headers_[value_row_id] = 0; + } else if (count < 0xFFFF) { + headers_[value_row_id] = count | (value_offset << 16); + } else { + bodies_[value_offset - 1] = count; + } + } + } + records.clear(); + } +} + +Column<Vector<Int>>::Column() : ColumnBase(), headers_(), bodies_() {} + +} // namespace impl +} // namespace grnxx Added: lib/grnxx/impl/column/column_vector_int.hpp (+72 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_int.hpp 2014-10-07 13:33:14 +0900 (773d7e7) @@ -0,0 +1,72 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_VECTOR_INT_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_VECTOR_INT_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +// TODO +template <> +class Column<Vector<Int>> : public ColumnBase { + public: + // -- Public API -- + + bool set(Error *error, Int row_id, const Datum &datum); + bool get(Error *error, Int row_id, Datum *datum) const; + + // -- Internal API -- + + // Create a new column. + // + // Returns a pointer to the column on success. + // On failure, returns nullptr and stores error information into "*error" if + // "error" != nullptr. + static unique_ptr<Column> create(Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options); + + ~Column(); + + bool set_default_value(Error *error, Int row_id); + void unset(Int row_id); + + void clear_references(Int row_id); + + // Return a value identified by "row_id". + // + // Assumes that "row_id" is valid. Otherwise, the result is undefined. + Vector<Int> get(Int row_id) const { + Int size = static_cast<Int>(headers_[row_id] & 0xFFFF); + if (size == 0) { + return Vector<Int>(nullptr, 0); + } + Int offset = static_cast<Int>(headers_[row_id] >> 16); + if (size < 0xFFFF) { + return Vector<Int>(&bodies_[offset], size); + } else { + // The size of a long vector is stored in front of the body. + size = bodies_[offset]; + return Vector<Int>(&bodies_[offset + 1], size); + } + } + + // Read values. + void read(ArrayCRef<Record> records, ArrayRef<Vector<Int>> values) const { + for (Int i = 0; i < records.size(); ++i) { + values.set(i, get(records.get_row_id(i))); + } + } + + private: + Array<UInt> headers_; + Array<Int> bodies_; + + Column(); +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_VECTOR_INT_HPP Added: lib/grnxx/impl/column/column_vector_text.cpp (+100 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_text.cpp 2014-10-07 13:33:14 +0900 (8bae356) @@ -0,0 +1,100 @@ +#include "grnxx/impl/column/column_vector_text.hpp" + +#include "grnxx/cursor.hpp" +#include "grnxx/impl/db.hpp" +#include "grnxx/impl/table.hpp" + +namespace grnxx { +namespace impl { + +bool Column<Vector<Text>>::set(Error *error, Int row_id, + const Datum &datum) { + if (datum.type() != TEXT_VECTOR_DATA) { + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong data type"); + return false; + } + if (!table_->test_row(error, row_id)) { + return false; + } + Vector<Text> value = datum.force_text_vector(); + if (value.size() == 0) { + headers_[row_id] = Header{ 0, 0 }; + return true; + } + Int text_headers_offset = text_headers_.size(); + if (!text_headers_.resize(error, text_headers_offset + value.size())) { + return false; + } + Int total_size = 0; + for (Int i = 0; i < value.size(); ++i) { + total_size += value[i].size(); + } + Int bodies_offset = bodies_.size(); + if (!bodies_.resize(error, bodies_offset + total_size)) { + return false; + } + headers_[row_id] = Header{ text_headers_offset, value.size() }; + for (Int i = 0; i < value.size(); ++i) { + text_headers_[text_headers_offset + i].offset = bodies_offset; + text_headers_[text_headers_offset + i].size = value[i].size(); + std::memcpy(&bodies_[bodies_offset], value[i].data(), value[i].size()); + bodies_offset += value[i].size(); + } + return true; +} + +bool Column<Vector<Text>>::get(Error *error, Int row_id, + Datum *datum) const { + if (!table_->test_row(error, row_id)) { + return false; + } + *datum = get(row_id); + return true; +} + +unique_ptr<Column<Vector<Text>>> Column<Vector<Text>>::create( + Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options) { + unique_ptr<Column> column(new (nothrow) Column); + if (!column) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return nullptr; + } + if (!column->initialize_base(error, table, name, + TEXT_VECTOR_DATA, options)) { + return nullptr; + } + if (!column->headers_.resize(error, table->max_row_id() + 1, + Header{ 0, 0 })) { + return nullptr; + } + return column; +} + +Column<Vector<Text>>::~Column() {} + +bool Column<Vector<Text>>::set_default_value(Error *error, + Int row_id) { + if (row_id >= headers_.size()) { + if (!headers_.resize(error, row_id + 1)) { + return false; + } + } + headers_[row_id] = Header{ 0, 0 }; + return true; +} + +void Column<Vector<Text>>::unset(Int row_id) { + headers_[row_id] = Header{ 0, 0 }; +} + +Column<Vector<Text>>::Column() + : ColumnBase(), + headers_(), + text_headers_(), + bodies_() {} + +} // namespace impl +} // namespace grnxx Added: lib/grnxx/impl/column/column_vector_text.hpp (+64 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/impl/column/column_vector_text.hpp 2014-10-07 13:33:14 +0900 (bb33ebe) @@ -0,0 +1,64 @@ +#ifndef GRNXX_IMPL_COLUMN_COLUMN_VECTOR_TEXT_HPP +#define GRNXX_IMPL_COLUMN_COLUMN_VECTOR_TEXT_HPP + +#include "grnxx/impl/column/column.hpp" + +namespace grnxx { +namespace impl { + +template <> +class Column<Vector<Text>> : public ColumnBase { + public: + // -- Public API -- + + bool set(Error *error, Int row_id, const Datum &datum); + bool get(Error *error, Int row_id, Datum *datum) const; + + // -- Internal API -- + + // Create a new column. + // + // Returns a pointer to the column on success. + // On failure, returns nullptr and stores error information into "*error" if + // "error" != nullptr. + static unique_ptr<Column> create(Error *error, + Table *table, + const StringCRef &name, + const ColumnOptions &options); + + ~Column(); + + bool set_default_value(Error *error, Int row_id); + void unset(Int row_id); + + // Return a value identified by "row_id". + // + // Assumes that "row_id" is valid. Otherwise, the result is undefined. + Vector<Text> get(Int row_id) const { + return Vector<Text>(&text_headers_[headers_[row_id].offset], + bodies_.data(), headers_[row_id].size); + } + + // Read values. + void read(ArrayCRef<Record> records, ArrayRef<Vector<Text>> values) const { + for (Int i = 0; i < records.size(); ++i) { + values.set(i, get(records.get_row_id(i))); + } + } + + private: + struct Header { + Int offset; + Int size; + }; + Array<Header> headers_; + Array<Header> text_headers_; + Array<char> bodies_; + + Column(); +}; + +} // namespace impl +} // namespace grnxx + +#endif // GRNXX_IMPL_COLUMN_COLUMN_VECTOR_TEXT_HPP Modified: lib/grnxx/impl/table.hpp (+1 -1) =================================================================== --- lib/grnxx/impl/table.hpp 2014-10-07 11:30:11 +0900 (b9ed720) +++ lib/grnxx/impl/table.hpp 2014-10-07 13:33:14 +0900 (59863ee) @@ -3,7 +3,7 @@ #include "grnxx/name.hpp" #include "grnxx/db.hpp" -#include "grnxx/impl/column/column_base.hpp" +#include "grnxx/impl/column.hpp" #include "grnxx/table.hpp" namespace grnxx { Modified: lib/grnxx/index.cpp (+5 -6) =================================================================== --- lib/grnxx/index.cpp 2014-10-07 11:30:11 +0900 (6ac6930) +++ lib/grnxx/index.cpp 2014-10-07 13:33:14 +0900 (7edb446) @@ -1,8 +1,7 @@ #include "grnxx/index.hpp" -#include "grnxx/column.hpp" -#include "grnxx/column_impl.hpp" #include "grnxx/cursor.hpp" +#include "grnxx/impl/column.hpp" #include "grnxx/table.hpp" #include "grnxx/tree_index.hpp" @@ -452,7 +451,7 @@ unique_ptr<TreeIndex<Bool>> TreeIndex<Bool>::create( if (!cursor) { return nullptr; } - auto typed_column = static_cast<ColumnImpl<Bool> *>(column); + auto typed_column = static_cast<impl::Column<Bool> *>(column); Array<Record> records; for ( ; ; ) { auto result = cursor->read(error, 1024, &records); @@ -610,7 +609,7 @@ unique_ptr<TreeIndex<Int>> TreeIndex<Int>::create( if (!cursor) { return nullptr; } - auto typed_column = static_cast<ColumnImpl<Int> *>(column); + auto typed_column = static_cast<impl::Column<Int> *>(column); Array<Record> records; for ( ; ; ) { auto result = cursor->read(error, 1024, &records); @@ -768,7 +767,7 @@ unique_ptr<TreeIndex<Float>> TreeIndex<Float>::create( if (!cursor) { return nullptr; } - auto typed_column = static_cast<ColumnImpl<Float> *>(column); + auto typed_column = static_cast<impl::Column<Float> *>(column); Array<Record> records; for ( ; ; ) { auto result = cursor->read(error, 1024, &records); @@ -937,7 +936,7 @@ unique_ptr<TreeIndex<Text>> TreeIndex<Text>::create( if (!cursor) { return nullptr; } - auto typed_column = static_cast<ColumnImpl<Text> *>(column); + auto typed_column = static_cast<impl::Column<Text> *>(column); Array<Record> records; for ( ; ; ) { auto result = cursor->read(error, 1024, &records);