[Groonga-commit] groonga/grnxx [master] Update the interface of grnxx::alpha::BlobVector.

Back to archive index

susumu.yata null+****@clear*****
Mon Dec 10 15:30:14 JST 2012


susumu.yata	2012-12-10 15:30:14 +0900 (Mon, 10 Dec 2012)

  New Revision: d93033e31adc1c614501c81563a291d1cb8ca5ad
  https://github.com/groonga/grnxx/commit/d93033e31adc1c614501c81563a291d1cb8ca5ad

  Log:
    Update the interface of grnxx::alpha::BlobVector.

  Modified files:
    lib/alpha/blob_vector.cpp
    lib/alpha/blob_vector.hpp
    test/test_alpha_blob_vector.cpp

  Modified: lib/alpha/blob_vector.cpp (+24 -40)
===================================================================
--- lib/alpha/blob_vector.cpp    2012-12-10 13:02:01 +0900 (8fc2c81)
+++ lib/alpha/blob_vector.cpp    2012-12-10 15:30:14 +0900 (010eabb)
@@ -73,22 +73,14 @@ std::unique_ptr<BlobVectorImpl> BlobVectorImpl::open(io::Pool pool,
   return vector;
 }
 
-const void *BlobVectorImpl::get_value(uint64_t id, uint64_t *length) {
+Blob BlobVectorImpl::get_value(uint64_t id) {
   const BlobVectorCell cell = table_[id];
   switch (cell.type()) {
     case BLOB_VECTOR_NULL: {
-      if (length) {
-        *length = 0;
-      }
-      return nullptr;
+      return Blob(nullptr);
     }
     case BLOB_VECTOR_SMALL: {
-      if (length) {
-        *length = cell.small_length();
-      }
-      // FIXME: The cell might be updated by other threads and processes.
-      //        This interface cannot solve this problem.
-      return table_[id].value();
+      return Blob(cell);
     }
     case BLOB_VECTOR_MEDIUM: {
       if (!value_store_) {
@@ -97,19 +89,12 @@ const void *BlobVectorImpl::get_value(uint64_t id, uint64_t *length) {
           value_store_.open(pool_, header_->value_store_block_id());
         }
       }
-      if (length) {
-        *length = cell.medium_length();
-      }
-      return &value_store_[cell.offset()];
+      return Blob(&value_store_[cell.offset()], cell.medium_length());
     }
     case BLOB_VECTOR_LARGE: {
-      const BlobVectorValueHeader *value_header =
-          static_cast<const BlobVectorValueHeader *>(
-              pool_.get_block_address(cell.block_id()));
-      if (length) {
-        *length = value_header->length();
-      }
-      return value_header + 1;
+      const auto value_header = static_cast<const BlobVectorValueHeader *>(
+          pool_.get_block_address(cell.block_id()));
+      return Blob(value_header + 1, value_header->length());
     }
     default: {
       GRNXX_ERROR() << "invalid value type";
@@ -118,17 +103,18 @@ const void *BlobVectorImpl::get_value(uint64_t id, uint64_t *length) {
   }
 }
 
-void BlobVectorImpl::set_value(uint64_t id, const void *ptr, uint64_t length) {
+void BlobVectorImpl::set_value(uint64_t id, const Blob &value) {
   BlobVectorCell new_cell;
-  if (!ptr) {
+  if (!value) {
     new_cell = BlobVectorCell::null_value_cell();
   } else {
-    if (length < BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH) {
-      new_cell = BlobVectorCell::small_value_cell(ptr, length);
-    } else if (length < BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH) {
-      new_cell = create_medium_value(ptr, length);
+    if (value.length() < BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH) {
+      new_cell = BlobVectorCell::small_value_cell(value.address(),
+                                                  value.length());
+    } else if (value.length() < BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH) {
+      new_cell = create_medium_value(value);
     } else {
-      new_cell = create_large_value(ptr, length);
+      new_cell = create_large_value(value);
     }
   }
 
@@ -223,8 +209,7 @@ void BlobVectorImpl::open_vector(io::Pool pool, uint32_t block_id) {
   table_.open(pool, header_->table_block_id());
 }
 
-BlobVectorCell BlobVectorImpl::create_medium_value(const void *ptr,
-                                                   uint64_t length) {
+BlobVectorCell BlobVectorImpl::create_medium_value(const Blob &value) {
   Lock lock(mutable_inter_thread_mutex());
 
   if (!value_store_) {
@@ -263,7 +248,7 @@ BlobVectorCell BlobVectorImpl::create_medium_value(const void *ptr,
       BLOB_VECTOR_VALUE_STORE_PAGE_SIZE - offset_in_page;
 
   // Reserve a new page if there is not enough space in the current page.
-  if (length > size_left_in_page) {
+  if (value.length() > size_left_in_page) {
     if (offset != 0) {
       // Freeze the current page if it is empty.
       const uint32_t page_id = static_cast<uint32_t>(
@@ -283,26 +268,25 @@ BlobVectorCell BlobVectorImpl::create_medium_value(const void *ptr,
     }
     index_store_[page_id].set_num_values(0);
   }
-  header_->set_next_value_offset(offset + length);
+  header_->set_next_value_offset(offset + value.length());
 
-  std::memcpy(&value_store_[offset], ptr, length);
+  std::memcpy(&value_store_[offset], value.address(), value.length());
 
   const uint32_t page_id = static_cast<uint32_t>(
       offset >> BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS);
   index_store_[page_id].set_num_values(index_store_[page_id].num_values() + 1);
 
-  return BlobVectorCell::medium_value_cell(offset, length);
+  return BlobVectorCell::medium_value_cell(offset, value.length());
 }
 
-BlobVectorCell BlobVectorImpl::create_large_value(const void *ptr,
-                                                  uint64_t length) {
+BlobVectorCell BlobVectorImpl::create_large_value(const Blob &value) {
   const io::BlockInfo *block_info =
-      pool_.create_block(sizeof(BlobVectorValueHeader) + length);
+      pool_.create_block(sizeof(BlobVectorValueHeader) + value.length());
   BlobVectorValueHeader *value_header =
       static_cast<BlobVectorValueHeader *>(
           pool_.get_block_address(*block_info));
-  value_header->set_length(length);
-  std::memcpy(value_header + 1, ptr, length);
+  value_header->set_length(value.length());
+  std::memcpy(value_header + 1, value.address(), value.length());
   register_large_value(block_info->id(), value_header);
   return BlobVectorCell::large_value_cell(block_info->id());
 }

  Modified: lib/alpha/blob_vector.hpp (+111 -11)
===================================================================
--- lib/alpha/blob_vector.hpp    2012-12-10 13:02:01 +0900 (346a015)
+++ lib/alpha/blob_vector.hpp    2012-12-10 15:30:14 +0900 (7697226)
@@ -271,6 +271,87 @@ class BlobVectorCell {
 static_assert(sizeof(BlobVectorCell) == sizeof(uint64_t),
               "sizeof(BlobVectorCell) != sizeof(uint64_t)");
 
+class Blob {
+ public:
+  Blob()
+    : address_(nullptr), length_(0),
+      cell_(BlobVectorCell::null_value_cell()) {}
+  explicit Blob(std::nullptr_t)
+    : address_(nullptr), length_(0),
+      cell_(BlobVectorCell::null_value_cell()) {}
+  Blob(const void *address, uint64_t length)
+    : address_(address), length_(length), cell_() {}
+  explicit Blob(BlobVectorCell small_value_cell)
+    : address_(), length_(), cell_(small_value_cell) {
+    address_ = cell_.value();
+    length_ = cell_.small_length();
+  }
+
+  // Note: address_ refers to the own value if it is small.
+  Blob(const Blob &rhs) : address_(), length_(rhs.length_), cell_(rhs.cell_) {
+    if (cell_.type() == BLOB_VECTOR_SMALL) {
+      address_ = cell_.value();
+    } else {
+      address_ = rhs.address_;
+    }
+  }
+  Blob &operator=(const Blob &rhs) {
+    length_ = rhs.length_;
+    cell_ = rhs.cell_;
+    if (cell_.type() == BLOB_VECTOR_SMALL) {
+      address_ = cell_.value();
+    } else {
+      address_ = rhs.address_;
+    }
+    return *this;
+  }
+
+  Blob &operator=(std::nullptr_t) {
+    return *this = Blob(nullptr);
+  }
+
+  explicit operator bool() const {
+    return static_cast<bool>(address_);
+  }
+
+  const void *address() const {
+    return address_;
+  }
+  uint64_t length() const {
+    return length_;
+  }
+
+  void set_address(const void *value) {
+    address_ = value;
+  }
+  void set_length(uint64_t value) {
+    length_ = value;
+  }
+
+ private:
+  const void *address_;
+  uint64_t length_;
+  BlobVectorCell cell_;
+};
+
+class BlobVector;
+
+class BlobRef {
+ public:
+  BlobRef(BlobVector *vector, uint64_t id) : vector_(vector), id_(id) {}
+
+  // vector_->get_value(id_);
+  operator Blob() const;
+
+  // vector_->set_value(id_, value);
+  BlobRef &operator=(std::nullptr_t);
+  BlobRef &operator=(const Blob &value);
+
+ private:
+  BlobVector *vector_;
+  uint64_t id_;
+};
+
 typedef Vector<BlobVectorCell> BlobVectorTable;
 
 typedef Vector<char, BLOB_VECTOR_VALUE_STORE_PAGE_SIZE,
@@ -289,10 +370,8 @@ class BlobVectorImpl {
   static std::unique_ptr<BlobVectorImpl> open(io::Pool pool,
                                               uint32_t block_id);
 
-  const void *get_value(uint64_t id, uint64_t *length);
-  void set_value(uint64_t id, const void *ptr, uint64_t length);
-
-  // TODO
+  Blob get_value(uint64_t id);
+  void set_value(uint64_t id, const Blob &value);
 
   uint32_t block_id() const {
     return block_info_->id();
@@ -317,8 +396,8 @@ class BlobVectorImpl {
   void create_vector(io::Pool pool);
   void open_vector(io::Pool pool, uint32_t block_id);
 
-  BlobVectorCell create_medium_value(const void *ptr, uint64_t length);
-  BlobVectorCell create_large_value(const void *ptr, uint64_t length);
+  BlobVectorCell create_medium_value(const Blob &value);
+  BlobVectorCell create_large_value(const Blob &value);
 
   void free_value(BlobVectorCell cell);
 
@@ -363,14 +442,21 @@ class BlobVector {
     *this = BlobVector();
   }
 
-  // TODO
-//  BlobVectorValueRef operator[](uint64_t id);
+  BlobRef operator[](uint64_t id) {
+    return BlobRef(this, id);
+  }
 
-  const void *get_value(uint64_t id, uint64_t *length = nullptr) {
-    return impl_->get_value(id, length);
+  Blob get_value(uint64_t id) {
+    return impl_->get_value(id);
+  }
+  void set_value(uint64_t id, std::nullptr_t) {
+    impl_->set_value(id, Blob(nullptr));
+  }
+  void set_value(uint64_t id, const Blob &value) {
+    impl_->set_value(id, value);
   }
   void set_value(uint64_t id, const void *ptr, uint64_t length) {
-    impl_->set_value(id, ptr, length);
+    impl_->set_value(id, Blob(ptr, length));
   }
 
   uint32_t block_id() const {
@@ -406,6 +492,20 @@ inline StringBuilder &operator<<(StringBuilder &builder,
   return vector.write_to(builder);
 }
 
+inline BlobRef::operator Blob() const {
+  return vector_->get_value(id_);
+}
+
+inline BlobRef &BlobRef::operator=(std::nullptr_t) {
+  vector_->set_value(id_, nullptr);
+  return *this;
+}
+
+inline BlobRef &BlobRef::operator=(const Blob &value) {
+  vector_->set_value(id_, value);
+  return *this;
+}
+
 }  // namespace alpha
 }  // namespace grnxx
 

  Modified: test/test_alpha_blob_vector.cpp (+68 -59)
===================================================================
--- test/test_alpha_blob_vector.cpp    2012-12-10 13:02:01 +0900 (75cc538)
+++ test/test_alpha_blob_vector.cpp    2012-12-10 15:30:14 +0900 (ca86216)
@@ -56,23 +56,23 @@ void test_basics() {
   vector.set_value(1000000000, values[3].c_str(), values[3].length());
   vector.set_value(1000000000000ULL, values[4].c_str(), values[4].length());
 
-  std::uint64_t length = 0;
-
-  assert(std::memcmp(vector.get_value(0, &length),
-                     values[0].c_str(), values[0].length()) == 0);
-  assert(length == values[0].length());
-  assert(std::memcmp(vector.get_value(1000, &length),
-                     values[1].c_str(), values[1].length()) == 0);
-  assert(length == values[1].length());
-  assert(std::memcmp(vector.get_value(1000000, &length),
-                     values[2].c_str(), values[2].length()) == 0);
-  assert(length == values[2].length());
-  assert(std::memcmp(vector.get_value(1000000000, &length),
-                     values[3].c_str(), values[3].length()) == 0);
-  assert(length == values[3].length());
-  assert(std::memcmp(vector.get_value(1000000000000ULL, &length),
-                     values[4].c_str(), values[4].length()) == 0);
-  assert(length == values[4].length());
+  grnxx::alpha::Blob blob;
+
+  assert(blob = vector[0]);
+  assert(blob.length() == values[0].length());
+  assert(std::memcmp(blob.address(), values[0].c_str(), blob.length()) == 0);
+  assert(blob = vector[1000]);
+  assert(blob.length() == values[1].length());
+  assert(std::memcmp(blob.address(), values[1].c_str(), blob.length()) == 0);
+  assert(blob = vector[1000000]);
+  assert(blob.length() == values[2].length());
+  assert(std::memcmp(blob.address(), values[2].c_str(), blob.length()) == 0);
+  assert(blob = vector[1000000000]);
+  assert(blob.length() == values[3].length());
+  assert(std::memcmp(blob.address(), values[3].c_str(), blob.length()) == 0);
+  assert(blob = vector[1000000000000ULL]);
+  assert(blob.length() == values[4].length());
+  assert(std::memcmp(blob.address(), values[4].c_str(), blob.length()) == 0);
 
   std::uint32_t block_id = vector.block_id();
 
@@ -84,24 +84,37 @@ void test_basics() {
 
   GRNXX_NOTICE() << "blob_vector = " << vector;
 
-  assert(std::memcmp(vector.get_value(0, &length),
-                     values[0].c_str(), values[0].length()) == 0);
-  assert(length == values[0].length());
-  assert(std::memcmp(vector.get_value(1000, &length),
-                     values[1].c_str(), values[1].length()) == 0);
-  assert(length == values[1].length());
-  assert(std::memcmp(vector.get_value(1000000, &length),
-                     values[2].c_str(), values[2].length()) == 0);
-  assert(length == values[2].length());
-  assert(std::memcmp(vector.get_value(1000000000, &length),
-                     values[3].c_str(), values[3].length()) == 0);
-  assert(length == values[3].length());
-  assert(std::memcmp(vector.get_value(1000000000000ULL, &length),
-                     values[4].c_str(), values[4].length()) == 0);
-  assert(length == values[4].length());
-
-  vector.set_value(0, nullptr, 0);
-  assert(!vector.get_value(0));
+  assert(blob = vector[0]);
+  assert(blob.length() == values[0].length());
+  assert(std::memcmp(blob.address(), values[0].c_str(), blob.length()) == 0);
+  assert(blob = vector[1000]);
+  assert(blob.length() == values[1].length());
+  assert(std::memcmp(blob.address(), values[1].c_str(), blob.length()) == 0);
+  assert(blob = vector[1000000]);
+  assert(blob.length() == values[2].length());
+  assert(std::memcmp(blob.address(), values[2].c_str(), blob.length()) == 0);
+  assert(blob = vector[1000000000]);
+  assert(blob.length() == values[3].length());
+  assert(std::memcmp(blob.address(), values[3].c_str(), blob.length()) == 0);
+  assert(blob = vector[1000000000000ULL]);
+  assert(blob.length() == values[4].length());
+  assert(std::memcmp(blob.address(), values[4].c_str(), blob.length()) == 0);
+
+  vector[0] = grnxx::alpha::Blob("banana", 6);
+  blob = vector[0];
+  assert(blob);
+  assert(blob.length() == 6);
+  assert(std::memcmp(blob.address(), "banana", 6) == 0);
+
+  grnxx::alpha::Blob blob2 = blob;
+  blob = nullptr;
+  assert(blob2);
+  assert(blob2.length() == 6);
+  assert(std::memcmp(blob2.address(), "banana", 6) == 0);
+
+  vector[0] = nullptr;
+  blob = vector[0];
+  assert(!blob);
 
   vector.close();
   pool.close();
@@ -134,21 +147,19 @@ void test_sequential_access(int num_loops,
 
     for (std::size_t i = 0; i < values.size(); ++i) {
       vector.set_value(i, values[i].c_str(), values[i].length());
-      std::uint64_t length;
-      const char *address =
-          static_cast<const char *>(vector.get_value(i, &length));
-      assert(address);
-      assert(length == values[i].length());
-      assert(std::memcmp(address, values[i].c_str(), length) == 0);
+      grnxx::alpha::Blob blob = vector[i];
+      assert(blob);
+      assert(blob.length() == values[i].length());
+      assert(std::memcmp(blob.address(), values[i].c_str(),
+                         blob.length()) == 0);
     }
 
     for (std::size_t i = 0; i < values.size(); ++i) {
-      std::uint64_t length;
-      const char *address =
-          static_cast<const char *>(vector.get_value(i, &length));
-      assert(address);
-      assert(length == values[i].length());
-      assert(std::memcmp(address, values[i].c_str(), length) == 0);
+      grnxx::alpha::Blob blob = vector[i];
+      assert(blob);
+      assert(blob.length() == values[i].length());
+      assert(std::memcmp(blob.address(), values[i].c_str(),
+                         blob.length()) == 0);
     }
 
     GRNXX_NOTICE() << "total_size = " << pool.header().total_size();
@@ -186,21 +197,19 @@ void test_random_access(int num_loops,
 
     for (std::size_t i = 0; i < values.size(); ++i) {
       vector.set_value(ids[i], values[i].c_str(), values[i].length());
-      std::uint64_t length;
-      const char *address =
-          static_cast<const char *>(vector.get_value(ids[i], &length));
-      assert(address);
-      assert(length == values[i].length());
-      assert(std::memcmp(address, values[i].c_str(), length) == 0);
+      grnxx::alpha::Blob blob = vector[ids[i]];
+      assert(blob);
+      assert(blob.length() == values[i].length());
+      assert(std::memcmp(blob.address(), values[i].c_str(),
+                         blob.length()) == 0);
     }
 
     for (std::size_t i = 0; i < values.size(); ++i) {
-      std::uint64_t length;
-      const char *address =
-          static_cast<const char *>(vector.get_value(ids[i], &length));
-      assert(address);
-      assert(length == values[i].length());
-      assert(std::memcmp(address, values[i].c_str(), length) == 0);
+      grnxx::alpha::Blob blob = vector[ids[i]];
+      assert(blob);
+      assert(blob.length() == values[i].length());
+      assert(std::memcmp(blob.address(), values[i].c_str(),
+                         blob.length()) == 0);
     }
 
     GRNXX_NOTICE() << "total_size = " << pool.header().total_size();
-------------- next part --------------
HTML����������������������������...
Download 



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