[Groonga-commit] groonga/grnxx at 2864000 [master] Add a draft of Column<Text>.

Back to archive index

susumu.yata null+****@clear*****
Tue Dec 16 10:41:25 JST 2014


susumu.yata	2014-11-10 17:05:05 +0900 (Mon, 10 Nov 2014)

  New Revision: 286400083efc103f43d6a034394d55b535eca3b8
  https://github.com/groonga/grnxx/commit/286400083efc103f43d6a034394d55b535eca3b8

  Message:
    Add a draft of Column<Text>.

  Modified files:
    lib/grnxx/impl/column/base.cpp
    lib/grnxx/impl/column/scalar.hpp
    lib/grnxx/impl/column/scalar/Makefile.am
    lib/grnxx/impl/column/scalar/int.cpp
    lib/grnxx/impl/column/scalar/text.cpp
    lib/grnxx/impl/column/scalar/text.hpp

  Modified: lib/grnxx/impl/column/base.cpp (+4 -4)
===================================================================
--- lib/grnxx/impl/column/base.cpp    2014-11-10 15:36:00 +0900 (b5b1634)
+++ lib/grnxx/impl/column/base.cpp    2014-11-10 17:05:05 +0900 (797c86f)
@@ -195,10 +195,10 @@ std::unique_ptr<ColumnBase> ColumnBase::create(
       column.reset(new impl::Column<GeoPoint>(table, name, options));
       break;
     }
-//    case TEXT_DATA: {
-//      column.reset(new impl::Column<Text>(table, name, options));
-//      break;
-//    }
+    case TEXT_DATA: {
+      column.reset(new impl::Column<Text>(table, name, options));
+      break;
+    }
 //    case BOOL_VECTOR_DATA: {
 //      column.reset(new impl::Column<Vector<Bool>>(table, name, options));
 //      break;

  Modified: lib/grnxx/impl/column/scalar.hpp (+1 -1)
===================================================================
--- lib/grnxx/impl/column/scalar.hpp    2014-11-10 15:36:00 +0900 (d6d9c3a)
+++ lib/grnxx/impl/column/scalar.hpp    2014-11-10 17:05:05 +0900 (f443aff)
@@ -5,6 +5,6 @@
 #include "grnxx/impl/column/scalar/float.hpp"
 #include "grnxx/impl/column/scalar/geo_point.hpp"
 #include "grnxx/impl/column/scalar/int.hpp"
-//#include "grnxx/impl/column/scalar/text.hpp"
+#include "grnxx/impl/column/scalar/text.hpp"
 
 #endif  // GRNXX_IMPL_COLUMN_SCALAR_HPP

  Modified: lib/grnxx/impl/column/scalar/Makefile.am (+2 -3)
===================================================================
--- lib/grnxx/impl/column/scalar/Makefile.am    2014-11-10 15:36:00 +0900 (1e31021)
+++ lib/grnxx/impl/column/scalar/Makefile.am    2014-11-10 17:05:05 +0900 (e381afc)
@@ -12,9 +12,8 @@ libgrnxx_impl_column_scalar_la_SOURCES =	\
 	bool.cpp				\
 	float.cpp				\
 	geo_point.cpp				\
-	int.cpp
-
-#	text.cpp
+	int.cpp					\
+	text.cpp
 
 libgrnxx_impl_column_scalar_includedir = ${includedir}/grnxx/impl/column/scalar
 libgrnxx_impl_column_scalar_include_HEADERS =	\

  Modified: lib/grnxx/impl/column/scalar/int.cpp (+1 -0)
===================================================================
--- lib/grnxx/impl/column/scalar/int.cpp    2014-11-10 15:36:00 +0900 (784892b)
+++ lib/grnxx/impl/column/scalar/int.cpp    2014-11-10 17:05:05 +0900 (4528629)
@@ -209,6 +209,7 @@ void Column<Int>::set_key(Int row_id, const Datum &key) {
   if (value_id >= values_.size()) {
     values_.resize(value_id + 1, Int::na());
   }
+  // TODO: N/A is not available.
   Int value = parse_datum(key);
   // TODO: Update indexes if exist.
 //  for (size_t i = 0; i < num_indexes(); ++i) try {

  Modified: lib/grnxx/impl/column/scalar/text.cpp (+354 -214)
===================================================================
--- lib/grnxx/impl/column/scalar/text.cpp    2014-11-10 15:36:00 +0900 (2db612a)
+++ lib/grnxx/impl/column/scalar/text.cpp    2014-11-10 17:05:05 +0900 (b1b6b66)
@@ -1,268 +1,408 @@
-#include "grnxx/impl/column/column_text.hpp"
+#include "grnxx/impl/column/scalar/text.hpp"
+
+#include <cstring>
+//#include <set>
 
-#include "grnxx/cursor.hpp"
 #include "grnxx/impl/db.hpp"
 #include "grnxx/impl/table.hpp"
-#include "grnxx/index.hpp"
-
-#include <set>
+//#include "grnxx/impl/index.hpp"
 
 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;
+Column<Text>::Column(Table *table,
+                     const String &name,
+                     const ColumnOptions &)
+    : ColumnBase(table, name, TEXT_DATA),
+      headers_(),
+      bodies_() {}
+
+Column<Text>::~Column() {}
+
+void Column<Text>::set(Int row_id, const Datum &datum) {
+  Text new_value = parse_datum(datum);
+  if (!table_->test_row(row_id)) {
+    throw "Invalid row ID";  // TODO
+  }
+  if (is_key_) {
+    if (new_value.is_na()) {
+      throw "N/A key";  // TODO
+    }
   }
-  if (!table_->test_row(error, row_id)) {
-    return false;
+  if (new_value.is_na()) {
+    unset(row_id);
+    return;
   }
   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;
+  if (old_value == new_value) {
+    return;
   }
-  return true;
-}
-
-bool Column<Text>::get(Error *error, Int row_id, Datum *datum) const {
-  if (!table_->test_row(error, row_id)) {
-    return false;
+  if (is_key_ && contains(datum)) {
+    throw "Key already exists";  // TODO
   }
-  *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 (!old_value.is_na()) {
+    // TODO: Remove the old value from indexes.
+//    for (size_t i = 0; i < num_indexes(); ++i) {
+//      indexes_[i]->remove(row_id, old_value);
+//    }
   }
-  if (!column->initialize_base(error, table, name, TEXT_DATA, options)) {
-    return nullptr;
+  size_t value_id = row_id.value();
+  if (value_id >= headers_.size()) {
+    headers_.resize(value_id + 1, na_header());
   }
-  if (!column->headers_.resize(error, table->max_row_id() + 1, 0)) {
-    return nullptr;
+  // TODO: Insert the new value into indexes.
+//  for (size_t i = 0; i < num_indexes(); ++i) try {
+//    indexes_[i]->insert(row_id, datum)) {
+//  } catch (...) {
+//    for (size_t j = 0; j < i; ++i) {
+//      indexes_[j]->remove(row_id, datum);
+//    }
+//    throw;
+//  }
+  // TODO: Error handling.
+  size_t offset = bodies_.size();
+  size_t size = new_value.size().value();
+  uint64_t header;
+  if (size < 0xFFFF) {
+    bodies_.resize(offset + size);
+    std::memcpy(&bodies_[offset], new_value.data(), size);
+    header = (offset << 16) | size;
+  } else {
+    // The size of a long text is stored in front of the body.
+    if ((offset % sizeof(uint64_t)) != 0) {
+      offset += sizeof(uint64_t) - (offset % sizeof(uint64_t));
+    }
+    bodies_.resize(offset + sizeof(uint64_t) + size);
+    *reinterpret_cast<uint64_t *>(&bodies_[offset]) = size;
+    std::memcpy(&bodies_[offset + sizeof(uint64_t)], new_value.data(), size);
+    header = (offset << 16) | 0xFFFF;
   }
-  return column;
+  headers_[value_id] = header;
 }
 
-Column<Text>::~Column() {}
+//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>::set_key_attribute(Error *error) {
-  if (has_key_attribute_) {
-    GRNXX_ERROR_SET(error, INVALID_OPERATION,
-                    "This column is a key column");
-    return false;
+void Column<Text>::get(Int row_id, Datum *datum) const {
+  size_t value_id = row_id.value();
+  if (value_id >= headers_.size()) {
+    *datum = Text::na();
+  } else {
+    // TODO
+    *datum = get(row_id);
   }
-  // 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;
+}
+
+bool Column<Text>::contains(const Datum &datum) const {
+  // TODO: Use an index if exists.
+  Text value = parse_datum(datum);
+  if (value.is_na()) {
+    for (size_t i = 0; i < headers_.size(); ++i) {
+      if (headers_[i] == na_header()) {
+        return true;
+      }
     }
-    Array<Record> records;
-    for ( ; ; ) {
-      auto result = cursor->read(nullptr, 1024, &records);
-      if (!result.is_ok) {
-        return false;
-      } else {
-        break;
+  } else {
+    for (size_t i = 0; i < headers_.size(); ++i) {
+      // TODO: Improve this.
+      if (get(Int(i)) == value) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+Int Column<Text>::find_one(const Datum &datum) const {
+  // TODO: Use an index if exists.
+  Text value = parse_datum(datum);
+  if (value.is_na()) {
+    for (size_t i = 0; i < headers_.size(); ++i) {
+      if (headers_[i] == na_header()) {
+        return Int(i);
       }
-      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;
-        }
+    }
+  } else {
+    for (size_t i = 0; i < headers_.size(); ++i) {
+      // TODO: Improve this.
+      if (get(Int(i)) == value) {
+        return Int(i);
       }
-      records.clear();
     }
-  } catch (...) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
   }
-  has_key_attribute_ = true;
-  return true;
+  return Int::na();
 }
 
-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;
+//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;
+//}
+
+void Column<Text>::set_key_attribute() {
+  if (is_key_) {
+    throw "Key column";  // TODO
   }
-  has_key_attribute_ = false;
-  return true;
+  throw "Not supported yet";  // TODO
 }
 
-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;
+//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;
+//}
+
+void Column<Text>::unset_key_attribute() {
+  if (!is_key_) {
+    throw "Not key column";  // TODO
   }
-  if (has_key_attribute_ && contains(key)) {
-    GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key duplicate");
-    return false;
+  is_key_ = true;
+}
+
+void Column<Text>::set_key(Int row_id, const Datum &key) {
+  if (!is_key_) {
+    throw "Not key column";  // TODO
   }
-  if (row_id >= headers_.size()) {
-    if (!headers_.resize(error, row_id + 1, 0)) {
-      return false;
-    }
+  if (contains(key)) {
+    throw "Key already exists";  // TODO
   }
-  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;
-    }
+  size_t value_id = row_id.value();
+  if (value_id >= headers_.size()) {
+    headers_.resize(value_id + 1, na_header());
   }
-  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();
+  // TODO: N/A is not available.
+  Text value = parse_datum(key);
+  // TODO: Update indexes if exist.
+//  for (size_t i = 0; i < num_indexes(); ++i) try {
+//    indexes_[i]->insert(row_id, value);
+//  } catch (...) {
+//    for (size_t j = 0; j < i; ++j) {
+//      indexes_[j]->remove(row_id, value);
+//    }
+//    throw;
+//  }
+  // TODO: Error handling.
+  size_t offset = bodies_.size();
+  size_t size = value.size().value();
+  uint64_t header;
+  if (size < 0xFFFF) {
+    bodies_.resize(offset + size);
+    std::memcpy(&bodies_[offset], value.data(), size);
+    header = (offset << 16) | 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;
+    if ((offset % sizeof(uint64_t)) != 0) {
+      offset += sizeof(uint64_t) - (offset % sizeof(uint64_t));
     }
-    *reinterpret_cast<Int *>(&bodies_[offset]) = value.size();
-    std::memcpy(&bodies_[offset + sizeof(Int)], value.data(), value.size());
+    bodies_.resize(offset + sizeof(uint64_t) + size);
+    *reinterpret_cast<uint64_t *>(&bodies_[offset]) = size;
+    std::memcpy(&bodies_[offset + sizeof(uint64_t)], value.data(), size);
     header = (offset << 16) | 0xFFFF;
   }
-  headers_[row_id] = header;
-  return true;
+  headers_[value_id] = header;
 }
 
-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;
-    }
+//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;
+//}
+
+void Column<Text>::unset(Int row_id) {
+  Text value = get(row_id);
+  if (!value.is_na()) {
+    // TODO: Update indexes if exist.
+//    for (size_t i = 0; i < num_indexes(); ++i) {
+//      indexes_[i]->remove(row_id, value);
+//    }
+    headers_[row_id.value()] = na_header();
   }
-  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));
+void Column<Text>::read(ArrayCRef<Record> records,
+                        ArrayRef<Text> values) const {
+  if (records.size() != values.size()) {
+    throw "Data size conflict";  // TODO
+  }
+  for (size_t i = 0; i < records.size(); ++i) {
+    values.set(i, get(records[i].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;
+Text Column<Text>::parse_datum(const Datum &datum) {
+  switch (datum.type()) {
+    case NA_DATA: {
+      return Text::na();
     }
-    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;
+    case TEXT_DATA: {
+      return datum.as_text();
     }
-    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();
+    default: {
+      throw "Wrong data type";  // TODO
     }
   }
-  return NULL_ROW_ID;
 }
 
-Column<Text>::Column() : ColumnBase(), headers_(), bodies_() {}
-
 }  // namespace impl
 }  // namespace grnxx

  Modified: lib/grnxx/impl/column/scalar/text.hpp (+53 -36)
===================================================================
--- lib/grnxx/impl/column/scalar/text.hpp    2014-11-10 15:36:00 +0900 (fb60e55)
+++ lib/grnxx/impl/column/scalar/text.hpp    2014-11-10 17:05:05 +0900 (52559ff)
@@ -1,71 +1,88 @@
 #ifndef GRNXX_IMPL_COLUMN_SCALAR_TEXT_HPP
 #define GRNXX_IMPL_COLUMN_SCALAR_TEXT_HPP
 
-#include "grnxx/impl/column/column.hpp"
+#include <limits>
+#include <cstdint>
+
+#include "grnxx/impl/column/base.hpp"
 
 namespace grnxx {
 namespace impl {
 
+template <typename T> class Column;
+
 template <>
-class Column<Text> : public impl::ColumnBase {
+class Column<Text> : public ColumnBase {
  public:
-  // -- Public API --
+  // -- 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;
+  Column(Table *table, const String &name, const ColumnOptions &options);
+  ~Column();
 
-  // -- Internal API --
+  void set(Int row_id, const Datum &datum);
+  void get(Int row_id, Datum *datum) const;
 
-  // 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);
+  bool contains(const Datum &datum) const;
+  Int find_one(const Datum &datum) const;
 
-  ~Column();
+  // -- Internal API (grnxx/impl/column/base.hpp) --
 
-  bool set_key_attribute(Error *error);
-  bool unset_key_attribute(Error *error);
+  void set_key_attribute();
+  void unset_key_attribute();
 
-  bool set_initial_key(Error *error, Int row_id, const Datum &key);
-  bool set_default_value(Error *error, Int row_id);
+  void set_key(Int row_id, const Datum &key);
   void unset(Int row_id);
-  Int find_one(const Datum &datum) const;
 
-  // Return a value identified by "row_id".
+  // -- Internal API --
+
+  // Return a value.
   //
-  // Assumes that "row_id" is valid. Otherwise, the result is undefined.
+  // If "row_id" is valid, returns the stored value.
+  // If "row_id" is invalid, returns N/A.
+  //
+  // TODO: Text cannot reuse allocated memory because of this interface.
   Text get(Int row_id) const {
-    Int size = static_cast<Int>(headers_[row_id] & 0xFFFF);
+    size_t value_id = row_id.value();
+    if (value_id >= headers_.size()) {
+      return Text::na();
+    }
+    if (headers_[value_id] == na_header()) {
+      return Text::na();
+    }
+    size_t size = headers_[value_id] & 0xFFFF;
     if (size == 0) {
-      return Text("", 0);
+      return Text(nullptr, 0);
     }
-    Int offset = static_cast<Int>(headers_[row_id] >> 16);
+    size_t offset = headers_[value_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);
+      size = *reinterpret_cast<const uint64_t *>(&bodies_[offset]);
+      return Text(&bodies_[offset + sizeof(uint64_t)], size);
     }
   }
-
+//  Text get(Int row_id) const {
+//    size_t value_id = row_id.value();
+//    if (value_id >= values_.size()) {
+//      return Text::na();
+//    }
+//    return values_[value_id];
+//  }
   // 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)));
-    }
-  }
+  //
+  // On failure, throws an exception.
+  void read(ArrayCRef<Record> records, ArrayRef<Text> values) const;
 
  private:
-  Array<UInt> headers_;
+  Array<uint64_t> headers_;
   Array<char> bodies_;
 
-  Column();
+  static constexpr uint64_t na_header() {
+    return std::numeric_limits<uint64_t>::max();
+  }
+
+  static Text parse_datum(const Datum &datum);
 };
 
 }  // namespace impl
-------------- next part --------------
HTML����������������������������...
다운로드 



More information about the Groonga-commit mailing list
Back to archive index