[Groonga-commit] groonga/grnxx at 9cf5d2f [master] Change the interface of grnxx::Array.

Back to archive index

susumu.yata null+****@clear*****
Wed May 29 11:45:43 JST 2013


susumu.yata	2013-05-29 11:45:43 +0900 (Wed, 29 May 2013)

  New Revision: 9cf5d2f46e3c005066985b6d257ba6ae55df8914
  https://github.com/groonga/grnxx/commit/9cf5d2f46e3c005066985b6d257ba6ae55df8914

  Message:
    Change the interface of grnxx::Array.

  Added files:
    lib/grnxx/array.cpp
  Modified files:
    lib/grnxx/Makefile.am
    lib/grnxx/array.hpp
    lib/grnxx/array_impl.cpp
    lib/grnxx/array_impl.hpp
    lib/grnxx/bit_array.hpp
    lib/grnxx/map/array_map.cpp
    lib/grnxx/map/array_map.hpp
    lib/grnxx/map/bytes_store.cpp
    test/test_array.cpp
    test/test_bit_array.cpp

  Modified: lib/grnxx/Makefile.am (+1 -0)
===================================================================
--- lib/grnxx/Makefile.am    2013-05-28 20:32:56 +0900 (f97e3e8)
+++ lib/grnxx/Makefile.am    2013-05-29 11:45:43 +0900 (97e8ef8)
@@ -19,6 +19,7 @@ libgrnxx_la_LIBADD =			\
 libgrnxx_la_LDFLAGS = @AM_LTLDFLAGS@
 
 libgrnxx_la_SOURCES =			\
+	array.cpp			\
 	array_impl.cpp			\
 	backtrace.cpp			\
 	broken_down_time.cpp		\

  Added: lib/grnxx/array.cpp (+24 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/array.cpp    2013-05-29 11:45:43 +0900 (2c81e02)
@@ -0,0 +1,24 @@
+/*
+  Copyright (C) 2012-2013  Brazil, Inc.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+#include "grnxx/array.hpp"
+
+namespace grnxx {
+
+// Nothing to do.
+
+}  // namespace grnxx

  Modified: lib/grnxx/array.hpp (+53 -361)
===================================================================
--- lib/grnxx/array.hpp    2013-05-28 20:32:56 +0900 (477b8fb)
+++ lib/grnxx/array.hpp    2013-05-29 11:45:43 +0900 (a23ebdb)
@@ -22,9 +22,10 @@
 
 #include <cstring>
 #include <memory>
+#include <new>
 
 #include "grnxx/array_impl.hpp"
-#include "grnxx/traits.hpp"
+#include "grnxx/logger.hpp"
 #include "grnxx/types.hpp"
 
 namespace grnxx {
@@ -39,284 +40,6 @@ template <typename T,
           uint64_t PAGE_SIZE = ARRAY_DEFAULT_PAGE_SIZE,
           uint64_t TABLE_SIZE = ARRAY_DEFAULT_TABLE_SIZE,
           uint64_t SECONDARY_TABLE_SIZE = ARRAY_DEFAULT_SECONDARY_TABLE_SIZE>
-class Array;
-
-// 1D array.
-template <typename T, uint64_t PAGE_SIZE>
-class Array<T, PAGE_SIZE, 1, 1> {
-  static_assert(PAGE_SIZE > 0, "PAGE_SIZE <= 0");
-
-  using ArrayImpl = Array1D;
-
- public:
-  using Value = typename Traits<T>::Type;
-  using ValueArg = typename Traits<T>::ArgumentType;
-
-  Array() : impl_() {}
-  ~Array() {}
-
-  // Return true iff the array is valid.
-  explicit operator bool() const {
-    return static_cast<bool>(impl_);
-  }
-
-  // Create an array.
-  bool create(Storage *storage, uint32_t storage_node_id) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::create(storage, storage_node_id, sizeof(Value), PAGE_SIZE));
-    if (!impl) {
-      return false;
-    }
-    impl_ = std::move(impl);
-    return true;
-  }
-
-  // Create an array with the default value.
-  bool create(Storage *storage, uint32_t storage_node_id,
-              ValueArg default_value) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
-                          &default_value, fill_page));
-    if (!impl) {
-      return false;
-    }
-    impl_ = std::move(impl);
-    return true;
-  }
-
-  // Open an array.
-  bool open(Storage *storage, uint32_t storage_node_id) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::open(storage, storage_node_id, sizeof(Value), PAGE_SIZE));
-    if (!impl) {
-      return false;
-    }
-    impl_ = std::move(impl);
-    return true;
-  }
-
-  // Unlink an array.
-  static bool unlink(Storage *storage, uint32_t storage_node_id) {
-    return ArrayImpl::unlink(storage, storage_node_id, sizeof(Value),
-                             PAGE_SIZE);
-  }
-
-  // Return the number of values in each page.
-  static constexpr uint64_t page_size() {
-    return PAGE_SIZE;
-  }
-  // Return the number of pages in each table.
-  static constexpr uint64_t table_size() {
-    return 1;
-  }
-  // Return the number of tables in each secondary table.
-  static constexpr uint64_t secondary_table_size() {
-    return 1;
-  }
-  // Return the number of values in Array.
-  static constexpr uint64_t size() {
-    return page_size() * table_size() * secondary_table_size();
-  }
-
-  // Return the storage node ID.
-  uint32_t storage_node_id() const {
-    return impl_->storage_node_id();
-  }
-
-  // Get a reference to a value.
-  Value &operator[](uint64_t value_id) {
-    Value * const page = get_page(value_id / PAGE_SIZE);
-    return page[value_id % PAGE_SIZE];
-  }
-
-  // Get a value and return true.
-  // The value is assigned to "*value" iff "value" != nullptr.
-  bool get(uint64_t value_id, Value *value) {
-    const Value * const page = get_page(value_id / PAGE_SIZE);
-    if (value) {
-      *value = page[value_id % PAGE_SIZE];
-    }
-    return true;
-  }
-
-  // Set a value and return true.
-  bool set(uint64_t value_id, ValueArg value) {
-    Value * const page = get_page(value_id / PAGE_SIZE);
-    page[value_id % PAGE_SIZE] = value;
-    return true;
-  }
-
-  // Get a value and return its address.
-  Value *get_value(uint64_t value_id) {
-    Value * const page = get_page(value_id / PAGE_SIZE);
-    return &page[value_id % PAGE_SIZE];
-  }
-
-  // Get a page and return its starting address.
-  Value *get_page(uint64_t) {
-    return impl_->get_page<Value>();
-  }
-
- private:
-  std::unique_ptr<ArrayImpl> impl_;
-
-  // This function is used to fill a new page with the default value.
-  static void fill_page(void *page, const void *value) {
-    Value *values = static_cast<Value *>(page);
-    for (uint64_t i = 0; i < PAGE_SIZE; ++i) {
-      std::memcpy(&values[i], value, sizeof(Value));
-    }
-  }
-};
-
-// 2D array.
-template <typename T, uint64_t PAGE_SIZE, uint64_t TABLE_SIZE>
-class Array<T, PAGE_SIZE, TABLE_SIZE, 1> {
-  static_assert((PAGE_SIZE > 0) && ((PAGE_SIZE & (PAGE_SIZE - 1)) == 0),
-                "PAGE_SIZE must be a power of two");
-  static_assert(TABLE_SIZE > 0, "TABLE_SIZE <= 0");
-
-  using ArrayImpl = Array2D;
-
- public:
-  using Value = typename Traits<T>::Type;
-  using ValueArg = typename Traits<T>::ArgumentType;
-
-  Array() : impl_() {}
-  ~Array() {}
-
-  // Return true iff the array is valid.
-  explicit operator bool() const {
-    return static_cast<bool>(impl_);
-  }
-
-  // Create an array.
-  bool create(Storage *storage, uint32_t storage_node_id) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
-                          TABLE_SIZE));
-    if (!impl) {
-      return false;
-    }
-    impl_ = std::move(impl);
-    return true;
-  }
-
-  // Create an array with the default value.
-  bool create(Storage *storage, uint32_t storage_node_id,
-              ValueArg default_value) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
-                          TABLE_SIZE, &default_value, fill_page));
-    if (!impl) {
-      return false;
-    }
-    impl_ = std::move(impl);
-    return true;
-  }
-
-  // Open an array.
-  bool open(Storage *storage, uint32_t storage_node_id) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::open(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
-                        TABLE_SIZE, fill_page));
-    if (!impl) {
-      return false;
-    }
-    impl_ = std::move(impl);
-    return true;
-  }
-
-  // Unlink an array.
-  static bool unlink(Storage *storage, uint32_t storage_node_id) {
-    return ArrayImpl::unlink(storage, storage_node_id, sizeof(Value),
-                             PAGE_SIZE, TABLE_SIZE);
-  }
-
-  // Return the number of values in each page.
-  static constexpr uint64_t page_size() {
-    return PAGE_SIZE;
-  }
-  // Return the number of pages in each table.
-  static constexpr uint64_t table_size() {
-    return TABLE_SIZE;
-  }
-  // Return the number of tables in each secondary table.
-  static constexpr uint64_t secondary_table_size() {
-    return 1;
-  }
-  // Return the number of values in Array.
-  static constexpr uint64_t size() {
-    return page_size() * table_size() * secondary_table_size();
-  }
-
-  // Return the storage node ID.
-  uint32_t storage_node_id() const {
-    return impl_->storage_node_id();
-  }
-
-  // Get a reference to a value.
-  // This function throws an exception on failure.
-  Value &operator[](uint64_t value_id) {
-    Value * const page =
-        impl_->get_page<Value, TABLE_SIZE>(value_id / PAGE_SIZE);
-    return page[value_id % PAGE_SIZE];
-  }
-
-  // Get a value and return true on success.
-  // The value is assigned to "*value" iff "value" != nullptr.
-  bool get(uint64_t value_id, Value *value) {
-    const Value * const page = get_page(value_id / PAGE_SIZE);
-    if (!page) {
-      return false;
-    }
-    if (value) {
-      *value = page[value_id % PAGE_SIZE];
-    }
-    return true;
-  }
-
-  // Set a value and return true on success.
-  bool set(uint64_t value_id, ValueArg value) {
-    Value * const page = get_page(value_id / PAGE_SIZE);
-    if (!page) {
-      return false;
-    }
-    page[value_id % PAGE_SIZE] = value;
-    return true;
-  }
-
-  // Get a value and return its address on success.
-  Value *get_value(uint64_t value_id) {
-    Value * const page = get_page(value_id / PAGE_SIZE);
-    if (!page) {
-      return nullptr;
-    }
-    return &page[value_id % PAGE_SIZE];
-  }
-
-  // Get a page and return its starting address on success.
-  Value *get_page(uint64_t page_id) {
-    return impl_->get_page_nothrow<Value, TABLE_SIZE>(page_id);
-  }
-
- private:
-  std::unique_ptr<ArrayImpl> impl_;
-
-  // This function is used to fill a new page with the default value.
-  static void fill_page(void *page, const void *value) {
-    Value *values = static_cast<Value *>(page);
-    for (uint64_t i = 0; i < PAGE_SIZE; ++i) {
-      std::memcpy(&values[i], value, sizeof(Value));
-    }
-  }
-};
-
-// 3D array.
-template <typename T,
-          uint64_t PAGE_SIZE,
-          uint64_t TABLE_SIZE,
-          uint64_t SECONDARY_TABLE_SIZE>
 class Array {
   static_assert((PAGE_SIZE > 0) && ((PAGE_SIZE & (PAGE_SIZE - 1)) == 0),
                 "PAGE_SIZE must be a power of two");
@@ -324,142 +47,111 @@ class Array {
                 "TABLE_SIZE must be a power of two");
   static_assert(SECONDARY_TABLE_SIZE > 0, "SECONDARY_TABLE_SIZE <= 0");
 
-  using ArrayImpl = Array3D;
+  using ArrayImpl = ArrayImpl<T, PAGE_SIZE, TABLE_SIZE, SECONDARY_TABLE_SIZE>;
 
  public:
-  using Value = typename Traits<T>::Type;
-  using ValueArg = typename Traits<T>::ArgumentType;
+  using Value = typename ArrayImpl::Value;
+  using ValueArg = typename ArrayImpl::ValueArg;
 
-  Array() : impl_() {}
   ~Array() {}
 
-  // Return true iff the array is valid.
-  explicit operator bool() const {
-    return static_cast<bool>(impl_);
-  }
-
   // Create an array.
-  bool create(Storage *storage, uint32_t storage_node_id) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
-                          TABLE_SIZE, SECONDARY_TABLE_SIZE));
-    if (!impl) {
-      return false;
+  static Array *create(Storage *storage, uint32_t storage_node_id) {
+    std::unique_ptr<Array> array(create_instance());
+    if (!array) {
+      return nullptr;
     }
-    impl_ = std::move(impl);
-    return true;
+    if (!array->impl_.create(storage, storage_node_id)) {
+      return nullptr;
+    }
+    return array.release();
   }
 
   // Create an array with the default value.
-  bool create(Storage *storage, uint32_t storage_node_id,
-              ValueArg default_value) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
-                          TABLE_SIZE, SECONDARY_TABLE_SIZE, &default_value,
-                          fill_page));
-    if (!impl) {
-      return false;
+  static Array *create(Storage *storage, uint32_t storage_node_id,
+                       ValueArg default_value) {
+    std::unique_ptr<Array> array(create_instance());
+    if (!array) {
+      return nullptr;
+    }
+    if (!array->impl_.create(storage, storage_node_id, default_value)) {
+      return nullptr;
     }
-    impl_ = std::move(impl);
-    return true;
+    return array.release();
   }
 
   // Open an array.
-  bool open(Storage *storage, uint32_t storage_node_id) {
-    std::unique_ptr<ArrayImpl> impl(
-        ArrayImpl::open(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
-                        TABLE_SIZE, SECONDARY_TABLE_SIZE, fill_page));
-    if (!impl) {
-      return false;
+  static Array *open(Storage *storage, uint32_t storage_node_id) {
+    std::unique_ptr<Array> array(create_instance());
+    if (!array) {
+      return nullptr;
+    }
+    if (!array->impl_.open(storage, storage_node_id)) {
+      return nullptr;
     }
-    impl_ = std::move(impl);
-    return true;
+    return array.release();
   }
 
   // Unlink an array.
   static bool unlink(Storage *storage, uint32_t storage_node_id) {
-    return ArrayImpl::unlink(storage, storage_node_id, sizeof(Value),
-                             PAGE_SIZE, TABLE_SIZE, SECONDARY_TABLE_SIZE);
+    return ArrayImpl::unlink(storage, storage_node_id);
   }
 
   // Return the number of values in each page.
   static constexpr uint64_t page_size() {
-    return PAGE_SIZE;
+    return ArrayImpl::page_size();
   }
   // Return the number of pages in each table.
   static constexpr uint64_t table_size() {
-    return TABLE_SIZE;
+    return ArrayImpl::table_size();
   }
   // Return the number of tables in each secondary table.
   static constexpr uint64_t secondary_table_size() {
-    return SECONDARY_TABLE_SIZE;
+    return ArrayImpl::secondary_table_size();
   }
   // Return the number of values in Array.
   static constexpr uint64_t size() {
-    return page_size() * table_size() * secondary_table_size();
+    return ArrayImpl::size();
   }
 
   // Return the storage node ID.
   uint32_t storage_node_id() const {
-    return impl_->storage_node_id();
-  }
-
-  // Get a reference to a value.
-  // This function throws an exception on failure.
-  Value &operator[](uint64_t value_id) {
-    Value * const page =
-        impl_->get_page<Value, TABLE_SIZE,
-                        SECONDARY_TABLE_SIZE>(value_id / PAGE_SIZE);
-    return page[value_id % PAGE_SIZE];
+    return impl_.storage_node_id();
   }
 
   // Get a value and return true on success.
   // The value is assigned to "*value" iff "value" != nullptr.
   bool get(uint64_t value_id, Value *value) {
-    const Value * const page = get_page(value_id / PAGE_SIZE);
-    if (!page) {
-      return false;
-    }
-    if (value) {
-      *value = page[value_id % PAGE_SIZE];
-    }
-    return true;
+    return impl_.get(value_id, value);
   }
-
   // Set a value and return true on success.
   bool set(uint64_t value_id, ValueArg value) {
-    Value * const page = get_page(value_id / PAGE_SIZE);
-    if (!page) {
-      return false;
-    }
-    page[value_id % PAGE_SIZE] = value;
-    return true;
+    return impl_.set(value_id, value);
   }
-
   // Get a value and return its address on success.
-  Value *get_value(uint64_t value_id) {
-    Value * const page = get_page(value_id / PAGE_SIZE);
-    if (!page) {
-      return nullptr;
-    }
-    return &page[value_id % PAGE_SIZE];
+  Value *get_pointer(uint64_t value_id) {
+    return impl_.get_pointer(value_id);
   }
-
   // Get a page and return its starting address on success.
   Value *get_page(uint64_t page_id) {
-    return impl_->get_page_nothrow<Value, TABLE_SIZE,
-                                   SECONDARY_TABLE_SIZE>(page_id);
+    return impl_.get_page(page_id);
   }
 
  private:
-  std::unique_ptr<ArrayImpl> impl_;
+  ArrayImpl impl_;
+
+  Array() : impl_() {}
 
-  // This function is used to fill a new page with the default value.
-  static void fill_page(void *page, const void *value) {
-    Value *values = static_cast<Value *>(page);
-    for (uint64_t i = 0; i < PAGE_SIZE; ++i) {
-      std::memcpy(&values[i], value, sizeof(Value));
+  static Array *create_instance() {
+    Array * const array = new (std::nothrow) Array;
+    if (!array) {
+      GRNXX_ERROR() << "new grnxx::Array failed: "
+                    << "value_size = " << sizeof(Value)
+                    << ", page_size = " << PAGE_SIZE
+                    << ", table_size = " << TABLE_SIZE
+                    << ", secondary_table_size = " << SECONDARY_TABLE_SIZE;
     }
+    return array;
   }
 };
 

  Modified: lib/grnxx/array_impl.cpp (+59 -196)
===================================================================
--- lib/grnxx/array_impl.cpp    2013-05-28 20:32:56 +0900 (9276522)
+++ lib/grnxx/array_impl.cpp    2013-05-29 11:45:43 +0900 (bb04e0f)
@@ -20,7 +20,6 @@
 #include <cstring>
 #include <new>
 
-#include "grnxx/exception.hpp"
 #include "grnxx/lock.hpp"
 #include "grnxx/logger.hpp"
 #include "grnxx/storage.hpp"
@@ -97,61 +96,13 @@ Array1D::Array1D()
 
 Array1D::~Array1D() {}
 
-Array1D *Array1D::create(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size,
-                         const void *default_value, FillPage fill_page) {
-  if (!storage) {
-    GRNXX_ERROR() << "invalid argument: storage = nullptr";
-    return nullptr;
-  }
-  std::unique_ptr<Array1D> array(new (std::nothrow) Array1D);
-  if (!array) {
-    GRNXX_ERROR() << "new grnxx::Array1D failed: "
-                  << "storage_node_id = " << storage_node_id
-                  << ", value_size = " << value_size
-                  << ", page_size = " << page_size
-                  << ", has_default_value = " << (default_value != nullptr);
-    return nullptr;
-  }
-  if (!array->create_array(storage, storage_node_id, value_size, page_size,
-                           default_value, fill_page)) {
-    return nullptr;
-  }
-  return array.release();
-}
-
-Array1D *Array1D::open(Storage *storage, uint32_t storage_node_id,
-                       uint64_t value_size, uint64_t page_size) {
+bool Array1D::create(Storage *storage, uint32_t storage_node_id,
+                     uint64_t value_size, uint64_t page_size,
+                     const void *default_value, FillPage fill_page) {
   if (!storage) {
     GRNXX_ERROR() << "invalid argument: storage = nullptr";
-    return nullptr;
-  }
-  std::unique_ptr<Array1D> array(new (std::nothrow) Array1D);
-  if (!array) {
-    GRNXX_ERROR() << "new grnxx::Array1D failed: "
-                  << "storage_node_id = " << storage_node_id
-                  << ", value_size = " << value_size
-                  << ", page_size = " << page_size;
-    return nullptr;
-  }
-  if (!array->open_array(storage, storage_node_id, value_size, page_size)) {
-    return nullptr;
-  }
-  return array.release();
-}
-
-bool Array1D::unlink(Storage *storage, uint32_t storage_node_id,
-                     uint64_t value_size, uint64_t page_size) {
-  Array1D array;
-  if (!array.open(storage, storage_node_id, value_size, page_size)) {
     return false;
   }
-  return storage->unlink_node(storage_node_id);
-}
-
-bool Array1D::create_array(Storage *storage, uint32_t storage_node_id,
-                           uint64_t value_size, uint64_t page_size,
-                           const void *default_value, FillPage fill_page) {
   StorageNode storage_node =
       storage->create_node(storage_node_id, sizeof(Array1DHeader));
   if (!storage_node) {
@@ -174,8 +125,12 @@ bool Array1D::create_array(Storage *storage, uint32_t storage_node_id,
   return true;
 }
 
-bool Array1D::open_array(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size) {
+bool Array1D::open(Storage *storage, uint32_t storage_node_id,
+                   uint64_t value_size, uint64_t page_size) {
+  if (!storage) {
+    GRNXX_ERROR() << "invalid argument: storage = nullptr";
+    return false;
+  }
   StorageNode storage_node = storage->open_node(storage_node_id);
   if (!storage_node) {
     return false;
@@ -205,6 +160,15 @@ bool Array1D::open_array(Storage *storage, uint32_t storage_node_id,
   return true;
 }
 
+bool Array1D::unlink(Storage *storage, uint32_t storage_node_id,
+                     uint64_t value_size, uint64_t page_size) {
+  Array1D array;
+  if (!array.open(storage, storage_node_id, value_size, page_size)) {
+    return false;
+  }
+  return storage->unlink_node(storage_node_id);
+}
+
 Array2D::Array2D()
     : storage_(nullptr),
       storage_node_id_(STORAGE_INVALID_NODE_ID),
@@ -217,71 +181,14 @@ Array2D::Array2D()
 
 Array2D::~Array2D() {}
 
-Array2D *Array2D::create(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size,
-                         uint64_t table_size,
-                         const void *default_value, FillPage fill_page) {
-  if (!storage) {
-    GRNXX_ERROR() << "invalid argument: storage = nullptr";
-    return nullptr;
-  }
-  std::unique_ptr<Array2D> array(new (std::nothrow) Array2D);
-  if (!array) {
-    GRNXX_ERROR() << "new grnxx::Array2D failed: "
-                  << "storage_node_id = " << storage_node_id
-                  << ", value_size = " << value_size
-                  << ", page_size = " << page_size
-                  << ", table_size = " << table_size
-                  << ", has_default_value = " << (default_value != nullptr);
-    return nullptr;
-  }
-  if (!array->create_array(storage, storage_node_id,
-                           value_size, page_size, table_size,
-                           default_value, fill_page)) {
-    return nullptr;
-  }
-  return array.release();
-}
-
-Array2D *Array2D::open(Storage *storage, uint32_t storage_node_id,
-                       uint64_t value_size, uint64_t page_size,
-                       uint64_t table_size, FillPage fill_page) {
+bool Array2D::create(Storage *storage, uint32_t storage_node_id,
+                     uint64_t value_size, uint64_t page_size,
+                     uint64_t table_size,
+                     const void *default_value, FillPage fill_page) {
   if (!storage) {
     GRNXX_ERROR() << "invalid argument: storage = nullptr";
     return nullptr;
   }
-  std::unique_ptr<Array2D> array(new (std::nothrow) Array2D);
-  if (!array) {
-    GRNXX_ERROR() << "new grnxx::Array2D failed: "
-                  << "storage_node_id = " << storage_node_id
-                  << ", value_size = " << value_size
-                  << ", page_size = " << page_size
-                  << ", table_size = " << table_size;
-    return nullptr;
-  }
-  if (!array->open_array(storage, storage_node_id,
-                         value_size, page_size, table_size,
-                         fill_page)) {
-    return nullptr;
-  }
-  return array.release();
-}
-
-bool Array2D::unlink(Storage *storage, uint32_t storage_node_id,
-                     uint64_t value_size, uint64_t page_size,
-                     uint64_t table_size) {
-  Array2D array;
-  if (!array.open(storage, storage_node_id,
-                  value_size, page_size, table_size, nullptr)) {
-    return false;
-  }
-  return storage->unlink_node(storage_node_id);
-}
-
-bool Array2D::create_array(Storage *storage, uint32_t storage_node_id,
-                           uint64_t value_size, uint64_t page_size,
-                           uint64_t table_size,
-                           const void *default_value, FillPage fill_page) {
   storage_ = storage;
   uint64_t storage_node_size = sizeof(Array2DHeader);
   if (default_value) {
@@ -323,9 +230,13 @@ bool Array2D::create_array(Storage *storage, uint32_t storage_node_id,
   return true;
 }
 
-bool Array2D::open_array(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size,
-                         uint64_t table_size, FillPage fill_page) {
+bool Array2D::open(Storage *storage, uint32_t storage_node_id,
+                   uint64_t value_size, uint64_t page_size,
+                   uint64_t table_size, FillPage fill_page) {
+  if (!storage) {
+    GRNXX_ERROR() << "invalid argument: storage = nullptr";
+    return false;
+  }
   storage_ = storage;
   StorageNode storage_node = storage->open_node(storage_node_id);
   if (!storage_node) {
@@ -371,14 +282,18 @@ bool Array2D::open_array(Storage *storage, uint32_t storage_node_id,
   return true;
 }
 
-void Array2D::initialize_page(uint64_t page_id) {
-  if (!initialize_page_nothrow(page_id)) {
-    GRNXX_ERROR() << "failed to initialize page: page_id = " << page_id;
-    GRNXX_THROW();
+bool Array2D::unlink(Storage *storage, uint32_t storage_node_id,
+                     uint64_t value_size, uint64_t page_size,
+                     uint64_t table_size) {
+  Array2D array;
+  if (!array.open(storage, storage_node_id,
+                  value_size, page_size, table_size, nullptr)) {
+    return false;
   }
+  return storage->unlink_node(storage_node_id);
 }
 
-bool Array2D::initialize_page_nothrow(uint64_t page_id) {
+bool Array2D::initialize_page(uint64_t page_id) {
   Lock inter_thread_lock(&mutex_);
   if (!table_cache_[page_id]) {
     StorageNode page_node;
@@ -422,73 +337,14 @@ Array3D::Array3D()
 
 Array3D::~Array3D() {}
 
-Array3D *Array3D::create(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size,
-                         uint64_t table_size, uint64_t secondary_table_size,
-                         const void *default_value, FillPage fill_page) {
-  if (!storage) {
-    GRNXX_ERROR() << "invalid argument: storage = nullptr";
-    return nullptr;
-  }
-  std::unique_ptr<Array3D> array(new (std::nothrow) Array3D);
-  if (!array) {
-    GRNXX_ERROR() << "new grnxx::Array3D failed: "
-                  << "storage_node_id = " << storage_node_id
-                  << ", value_size = " << value_size
-                  << ", page_size = " << page_size
-                  << ", table_size = " << table_size
-                  << ", secondary_table_size = " << secondary_table_size
-                  << ", has_default_value = " << (default_value != nullptr);
-    return nullptr;
-  }
-  if (!array->create_array(storage, storage_node_id, value_size, page_size,
-                           table_size, secondary_table_size,
-                           default_value, fill_page)) {
-    return nullptr;
-  }
-  return array.release();
-}
-
-Array3D *Array3D::open(Storage *storage, uint32_t storage_node_id,
-                       uint64_t value_size, uint64_t page_size,
-                       uint64_t table_size, uint64_t secondary_table_size,
-                       FillPage fill_page) {
+bool Array3D::create(Storage *storage, uint32_t storage_node_id,
+                     uint64_t value_size, uint64_t page_size,
+                     uint64_t table_size, uint64_t secondary_table_size,
+                     const void *default_value, FillPage fill_page) {
   if (!storage) {
     GRNXX_ERROR() << "invalid argument: storage = nullptr";
     return nullptr;
   }
-  std::unique_ptr<Array3D> array(new (std::nothrow) Array3D);
-  if (!array) {
-    GRNXX_ERROR() << "new grnxx::Array3D failed: "
-                  << "storage_node_id = " << storage_node_id
-                  << ", value_size = " << value_size
-                  << ", page_size = " << page_size
-                  << ", table_size = " << table_size
-                  << ", secondary_table_size = " << secondary_table_size;
-    return nullptr;
-  }
-  if (!array->open_array(storage, storage_node_id, value_size, page_size,
-                         table_size, secondary_table_size, fill_page)) {
-    return nullptr;
-  }
-  return array.release();
-}
-
-bool Array3D::unlink(Storage *storage, uint32_t storage_node_id,
-                     uint64_t value_size, uint64_t page_size,
-                     uint64_t table_size, uint64_t secondary_table_size) {
-  Array3D array;
-  if (!array.open(storage, storage_node_id, value_size, page_size,
-                  table_size, secondary_table_size, nullptr)) {
-    return false;
-  }
-  return storage->unlink_node(storage_node_id);
-}
-
-bool Array3D::create_array(Storage *storage, uint32_t storage_node_id,
-                           uint64_t value_size, uint64_t page_size,
-                           uint64_t table_size, uint64_t secondary_table_size,
-                           const void *default_value, FillPage fill_page) {
   storage_ = storage;
   uint64_t storage_node_size = sizeof(Array3DHeader);
   if (default_value) {
@@ -519,10 +375,14 @@ bool Array3D::create_array(Storage *storage, uint32_t storage_node_id,
   return true;
 }
 
-bool Array3D::open_array(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size,
-                         uint64_t table_size, uint64_t secondary_table_size,
-                         FillPage fill_page) {
+bool Array3D::open(Storage *storage, uint32_t storage_node_id,
+                   uint64_t value_size, uint64_t page_size,
+                   uint64_t table_size, uint64_t secondary_table_size,
+                   FillPage fill_page) {
+  if (!storage) {
+    GRNXX_ERROR() << "invalid argument: storage = nullptr";
+    return nullptr;
+  }
   storage_ = storage;
   StorageNode storage_node = storage->open_node(storage_node_id);
   if (!storage_node) {
@@ -569,15 +429,18 @@ bool Array3D::open_array(Storage *storage, uint32_t storage_node_id,
   return true;
 }
 
-void Array3D::initialize_page(uint64_t table_id, uint64_t page_id) {
-  if (!initialize_page_nothrow(table_id, page_id)) {
-    GRNXX_ERROR() << "failed to initialize page: table_id = " << table_id
-                  << ", page_id = " << page_id;
-    GRNXX_THROW();
+bool Array3D::unlink(Storage *storage, uint32_t storage_node_id,
+                     uint64_t value_size, uint64_t page_size,
+                     uint64_t table_size, uint64_t secondary_table_size) {
+  Array3D array;
+  if (!array.open(storage, storage_node_id, value_size, page_size,
+                  table_size, secondary_table_size, nullptr)) {
+    return false;
   }
+  return storage->unlink_node(storage_node_id);
 }
 
-bool Array3D::initialize_page_nothrow(uint64_t table_id, uint64_t page_id) {
+bool Array3D::initialize_page(uint64_t table_id, uint64_t page_id) {
   if (!table_caches_[table_id]) {
     if (!initialize_table(table_id)) {
       return false;

  Modified: lib/grnxx/array_impl.hpp (+366 -73)
===================================================================
--- lib/grnxx/array_impl.hpp    2013-05-28 20:32:56 +0900 (e623075)
+++ lib/grnxx/array_impl.hpp    2013-05-29 11:45:43 +0900 (b972d99)
@@ -20,9 +20,11 @@
 
 #include "grnxx/features.hpp"
 
+#include <cstring>
 #include <memory>
 
 #include "grnxx/mutex.hpp"
+#include "grnxx/traits.hpp"
 #include "grnxx/types.hpp"
 
 namespace grnxx {
@@ -40,13 +42,12 @@ class Array1D {
   Array1D();
   ~Array1D();
 
-  static Array1D *create(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size,
-                         const void *default_value = nullptr,
-                         FillPage fill_page = nullptr);
-
-  static Array1D *open(Storage *storage, uint32_t storage_node_id,
-                       uint64_t value_size, uint64_t page_size);
+  bool create(Storage *storage, uint32_t storage_node_id,
+              uint64_t value_size, uint64_t page_size,
+              const void *default_value = nullptr,
+              FillPage fill_page = nullptr);
+  bool open(Storage *storage, uint32_t storage_node_id,
+            uint64_t value_size, uint64_t page_size);
 
   static bool unlink(Storage *storage, uint32_t storage_node_id,
                      uint64_t value_size, uint64_t page_size);
@@ -64,13 +65,6 @@ class Array1D {
   uint32_t storage_node_id_;
   Array1DHeader *header_;
   void *page_;
-
-  bool create_array(Storage *storage, uint32_t storage_node_id,
-                    uint64_t value_size, uint64_t page_size,
-                    const void *default_value, FillPage fill_page);
-  bool open_array(Storage *storage, uint32_t storage_node_id,
-                  uint64_t value_size, uint64_t page_size);
-
 };
 
 class Array2D {
@@ -80,15 +74,14 @@ class Array2D {
   Array2D();
   ~Array2D();
 
-  static Array2D *create(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size,
-                         uint64_t table_size,
-                         const void *default_value = nullptr,
-                         FillPage fill_page = nullptr);
-
-  static Array2D *open(Storage *storage, uint32_t storage_node_id,
-                       uint64_t value_size, uint64_t page_size,
-                       uint64_t table_size, FillPage fill_page);
+  bool create(Storage *storage, uint32_t storage_node_id,
+              uint64_t value_size, uint64_t page_size,
+              uint64_t table_size,
+              const void *default_value = nullptr,
+              FillPage fill_page = nullptr);
+  bool open(Storage *storage, uint32_t storage_node_id,
+            uint64_t value_size, uint64_t page_size,
+            uint64_t table_size, FillPage fill_page);
 
   static bool unlink(Storage *storage, uint32_t storage_node_id,
                      uint64_t value_size, uint64_t page_size,
@@ -101,15 +94,7 @@ class Array2D {
   template <typename T, uint64_t TABLE_SIZE>
   T *get_page(uint64_t page_id) {
     if (!table_cache_[page_id]) {
-      initialize_page(page_id);
-    }
-    return static_cast<T *>(table_cache_[page_id]);
-  }
-
-  template <typename T, uint64_t TABLE_SIZE>
-  T *get_page_nothrow(uint64_t page_id) {
-    if (!table_cache_[page_id]) {
-      if (!initialize_page_nothrow(page_id)) {
+      if (!initialize_page(page_id)) {
         return nullptr;
       }
     }
@@ -126,16 +111,7 @@ class Array2D {
   std::unique_ptr<void *[]> table_cache_;
   Mutex mutex_;
 
-  bool create_array(Storage *storage, uint32_t storage_node_id,
-                    uint64_t value_size, uint64_t page_size,
-                    uint64_t table_size,
-                    const void *default_value, FillPage fill_page);
-  bool open_array(Storage *storage, uint32_t storage_node_id,
-                  uint64_t value_size, uint64_t page_size, uint64_t table_size,
-                  FillPage fill_page);
-
-  void initialize_page(uint64_t page_id);
-  bool initialize_page_nothrow(uint64_t page_id);
+  bool initialize_page(uint64_t page_id);
 };
 
 class Array3D {
@@ -145,16 +121,16 @@ class Array3D {
   Array3D();
   ~Array3D();
 
-  static Array3D *create(Storage *storage, uint32_t storage_node_id,
-                         uint64_t value_size, uint64_t page_size,
-                         uint64_t table_size, uint64_t secondary_table_size,
-                         const void *default_value = nullptr,
-                         FillPage fill_page = nullptr);
+  bool create(Storage *storage, uint32_t storage_node_id,
+               uint64_t value_size, uint64_t page_size,
+               uint64_t table_size, uint64_t secondary_table_size,
+               const void *default_value = nullptr,
+               FillPage fill_page = nullptr);
 
-  static Array3D *open(Storage *storage, uint32_t storage_node_id,
-                       uint64_t value_size, uint64_t page_size,
-                       uint64_t table_size, uint64_t secondary_table_size,
-                       FillPage fill_page);
+  bool open(Storage *storage, uint32_t storage_node_id,
+            uint64_t value_size, uint64_t page_size,
+            uint64_t table_size, uint64_t secondary_table_size,
+            FillPage fill_page);
 
   static bool unlink(Storage *storage, uint32_t storage_node_id,
                      uint64_t value_size, uint64_t page_size,
@@ -169,17 +145,7 @@ class Array3D {
     const uint64_t table_id = page_id / TABLE_SIZE;
     page_id %= TABLE_SIZE;
     if (!table_caches_[table_id] || !table_caches_[table_id][page_id]) {
-      initialize_page(table_id, page_id);
-    }
-    return static_cast<T *>(table_caches_[table_id][page_id]);
-  }
-
-  template <typename T, uint64_t TABLE_SIZE, uint64_t SECONDARY_TABLE_SIZE>
-  T *get_page_nothrow(uint64_t page_id) {
-    const uint64_t table_id = page_id / TABLE_SIZE;
-    page_id %= TABLE_SIZE;
-    if (!table_caches_[table_id] || !table_caches_[table_id][page_id]) {
-      if (!initialize_page_nothrow(table_id, page_id)) {
+      if (!initialize_page(table_id, page_id)) {
         return nullptr;
       }
     }
@@ -198,21 +164,348 @@ class Array3D {
   Mutex table_mutex_;
   Mutex secondary_table_mutex_;
 
-  bool create_array(Storage *storage, uint32_t storage_node_id,
-                    uint64_t value_size, uint64_t page_size,
-                    uint64_t table_size, uint64_t secondary_table_size,
-                    const void *default_value, FillPage fill_page);
-  bool open_array(Storage *storage, uint32_t storage_node_id,
-                  uint64_t value_size, uint64_t page_size,
-                  uint64_t table_size, uint64_t secondary_table_size,
-                  FillPage fill_page);
-
-  void initialize_page(uint64_t table_id, uint64_t page_id);
-  bool initialize_page_nothrow(uint64_t table_id, uint64_t page_id);
+  bool initialize_page(uint64_t table_id, uint64_t page_id);
   bool initialize_table(uint64_t table_id);
   bool initialize_secondary_table();
 };
 
+template <typename T,
+          uint64_t PAGE_SIZE,
+          uint64_t TABLE_SIZE,
+          uint64_t SECONDARY_TABLE_SIZE>
+class ArrayImpl;
+
+// 1D array.
+template <typename T, uint64_t PAGE_SIZE>
+class ArrayImpl<T, PAGE_SIZE, 1, 1> {
+  static_assert(PAGE_SIZE > 0, "PAGE_SIZE <= 0");
+
+ public:
+  using Value = typename Traits<T>::Type;
+  using ValueArg = typename Traits<T>::ArgumentType;
+
+  ArrayImpl() : impl_() {}
+  ~ArrayImpl() {}
+
+  // Return true iff the array is valid.
+  explicit operator bool() const {
+    return static_cast<bool>(impl_);
+  }
+
+  // Create an array.
+  bool create(Storage *storage, uint32_t storage_node_id) {
+    return impl_.create(storage, storage_node_id, sizeof(Value), PAGE_SIZE);
+  }
+  // Create an array with the default value.
+  bool create(Storage *storage, uint32_t storage_node_id,
+              ValueArg default_value) {
+    return impl_.create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
+                        &default_value, fill_page);
+  }
+  // Open an array.
+  bool open(Storage *storage, uint32_t storage_node_id) {
+    return impl_.open(storage, storage_node_id, sizeof(Value), PAGE_SIZE);
+  }
+
+  // Unlink an array.
+  static bool unlink(Storage *storage, uint32_t storage_node_id) {
+    return Array1D::unlink(storage, storage_node_id, sizeof(Value), PAGE_SIZE);
+  }
+
+  // Return the number of values in each page.
+  static constexpr uint64_t page_size() {
+    return PAGE_SIZE;
+  }
+  // Return the number of pages in each table.
+  static constexpr uint64_t table_size() {
+    return 1;
+  }
+  // Return the number of tables in each secondary table.
+  static constexpr uint64_t secondary_table_size() {
+    return 1;
+  }
+  // Return the number of values in Array.
+  static constexpr uint64_t size() {
+    return page_size() * table_size() * secondary_table_size();
+  }
+
+  // Return the storage node ID.
+  uint32_t storage_node_id() const {
+    return impl_.storage_node_id();
+  }
+
+  // Get a value and return true.
+  // The value is assigned to "*value" iff "value" != nullptr.
+  bool get(uint64_t value_id, Value *value) {
+    const Value * const page = get_page(value_id / PAGE_SIZE);
+    if (value) {
+      *value = page[value_id % PAGE_SIZE];
+    }
+    return true;
+  }
+
+  // Set a value and return true.
+  bool set(uint64_t value_id, ValueArg value) {
+    Value * const page = get_page(value_id / PAGE_SIZE);
+    page[value_id % PAGE_SIZE] = value;
+    return true;
+  }
+
+  // Get a value and return its address.
+  Value *get_pointer(uint64_t value_id) {
+    Value * const page = get_page(value_id / PAGE_SIZE);
+    return &page[value_id % PAGE_SIZE];
+  }
+
+  // Get a page and return its starting address.
+  Value *get_page(uint64_t) {
+    return impl_.get_page<Value>();
+  }
+
+ private:
+  Array1D impl_;
+
+  // This function is used to fill a new page with the default value.
+  static void fill_page(void *page, const void *value) {
+    Value *values = static_cast<Value *>(page);
+    for (uint64_t i = 0; i < PAGE_SIZE; ++i) {
+      std::memcpy(&values[i], value, sizeof(Value));
+    }
+  }
+};
+
+// 2D array.
+template <typename T, uint64_t PAGE_SIZE, uint64_t TABLE_SIZE>
+class ArrayImpl<T, PAGE_SIZE, TABLE_SIZE, 1> {
+  static_assert((PAGE_SIZE > 0) && ((PAGE_SIZE & (PAGE_SIZE - 1)) == 0),
+                "PAGE_SIZE must be a power of two");
+  static_assert(TABLE_SIZE > 0, "TABLE_SIZE <= 0");
+
+ public:
+  using Value = typename Traits<T>::Type;
+  using ValueArg = typename Traits<T>::ArgumentType;
+
+  ArrayImpl() : impl_() {}
+  ~ArrayImpl() {}
+
+  // Return true iff the array is valid.
+  explicit operator bool() const {
+    return static_cast<bool>(impl_);
+  }
+
+  // Create an array.
+  bool create(Storage *storage, uint32_t storage_node_id) {
+    return impl_.create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
+                        TABLE_SIZE);
+  }
+  // Create an array with the default value.
+  bool create(Storage *storage, uint32_t storage_node_id,
+              ValueArg default_value) {
+    return impl_.create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
+                        TABLE_SIZE, &default_value, fill_page);
+  }
+  // Open an array.
+  bool open(Storage *storage, uint32_t storage_node_id) {
+    return impl_.open(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
+                      TABLE_SIZE, fill_page);
+  }
+
+  // Unlink an array.
+  static bool unlink(Storage *storage, uint32_t storage_node_id) {
+    return Array2D::unlink(storage, storage_node_id, sizeof(Value),
+                           PAGE_SIZE, TABLE_SIZE);
+  }
+
+  // Return the number of values in each page.
+  static constexpr uint64_t page_size() {
+    return PAGE_SIZE;
+  }
+  // Return the number of pages in each table.
+  static constexpr uint64_t table_size() {
+    return TABLE_SIZE;
+  }
+  // Return the number of tables in each secondary table.
+  static constexpr uint64_t secondary_table_size() {
+    return 1;
+  }
+  // Return the number of values in Array.
+  static constexpr uint64_t size() {
+    return page_size() * table_size() * secondary_table_size();
+  }
+
+  // Return the storage node ID.
+  uint32_t storage_node_id() const {
+    return impl_.storage_node_id();
+  }
+
+  // Get a value and return true on success.
+  // The value is assigned to "*value" iff "value" != nullptr.
+  bool get(uint64_t value_id, Value *value) {
+    const Value * const page = get_page(value_id / PAGE_SIZE);
+    if (!page) {
+      return false;
+    }
+    if (value) {
+      *value = page[value_id % PAGE_SIZE];
+    }
+    return true;
+  }
+
+  // Set a value and return true on success.
+  bool set(uint64_t value_id, ValueArg value) {
+    Value * const page = get_page(value_id / PAGE_SIZE);
+    if (!page) {
+      return false;
+    }
+    page[value_id % PAGE_SIZE] = value;
+    return true;
+  }
+
+  // Get a value and return its address on success.
+  Value *get_pointer(uint64_t value_id) {
+    Value * const page = get_page(value_id / PAGE_SIZE);
+    if (!page) {
+      return nullptr;
+    }
+    return &page[value_id % PAGE_SIZE];
+  }
+
+  // Get a page and return its starting address on success.
+  Value *get_page(uint64_t page_id) {
+    return impl_.get_page<Value, TABLE_SIZE>(page_id);
+  }
+
+ private:
+  Array2D impl_;
+
+  // This function is used to fill a new page with the default value.
+  static void fill_page(void *page, const void *value) {
+    Value *values = static_cast<Value *>(page);
+    for (uint64_t i = 0; i < PAGE_SIZE; ++i) {
+      std::memcpy(&values[i], value, sizeof(Value));
+    }
+  }
+};
+
+// 3D array.
+template <typename T,
+          uint64_t PAGE_SIZE,
+          uint64_t TABLE_SIZE,
+          uint64_t SECONDARY_TABLE_SIZE>
+class ArrayImpl {
+  static_assert((PAGE_SIZE > 0) && ((PAGE_SIZE & (PAGE_SIZE - 1)) == 0),
+                "PAGE_SIZE must be a power of two");
+  static_assert((TABLE_SIZE > 0) && ((TABLE_SIZE & (TABLE_SIZE - 1)) == 0),
+                "TABLE_SIZE must be a power of two");
+  static_assert(SECONDARY_TABLE_SIZE > 0, "SECONDARY_TABLE_SIZE <= 0");
+
+ public:
+  using Value = typename Traits<T>::Type;
+  using ValueArg = typename Traits<T>::ArgumentType;
+
+  ArrayImpl() : impl_() {}
+  ~ArrayImpl() {}
+
+  // Return true iff the array is valid.
+  explicit operator bool() const {
+    return static_cast<bool>(impl_);
+  }
+
+  // Create an array.
+  bool create(Storage *storage, uint32_t storage_node_id) {
+    return impl_.create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
+                        TABLE_SIZE, SECONDARY_TABLE_SIZE);
+  }
+  // Create an array with the default value.
+  bool create(Storage *storage, uint32_t storage_node_id,
+              ValueArg default_value) {
+    return impl_.create(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
+                        TABLE_SIZE, SECONDARY_TABLE_SIZE, &default_value,
+                        fill_page);
+  }
+  // Open an array.
+  bool open(Storage *storage, uint32_t storage_node_id) {
+    return impl_.open(storage, storage_node_id, sizeof(Value), PAGE_SIZE,
+                      TABLE_SIZE, SECONDARY_TABLE_SIZE, fill_page);
+  }
+
+  // Unlink an array.
+  static bool unlink(Storage *storage, uint32_t storage_node_id) {
+    return Array3D::unlink(storage, storage_node_id, sizeof(Value),
+                           PAGE_SIZE, TABLE_SIZE, SECONDARY_TABLE_SIZE);
+  }
+
+  // Return the number of values in each page.
+  static constexpr uint64_t page_size() {
+    return PAGE_SIZE;
+  }
+  // Return the number of pages in each table.
+  static constexpr uint64_t table_size() {
+    return TABLE_SIZE;
+  }
+  // Return the number of tables in each secondary table.
+  static constexpr uint64_t secondary_table_size() {
+    return SECONDARY_TABLE_SIZE;
+  }
+  // Return the number of values in Array.
+  static constexpr uint64_t size() {
+    return page_size() * table_size() * secondary_table_size();
+  }
+
+  // Return the storage node ID.
+  uint32_t storage_node_id() const {
+    return impl_.storage_node_id();
+  }
+
+  // Get a value and return true on success.
+  // The value is assigned to "*value" iff "value" != nullptr.
+  bool get(uint64_t value_id, Value *value) {
+    const Value * const page = get_page(value_id / PAGE_SIZE);
+    if (!page) {
+      return false;
+    }
+    if (value) {
+      *value = page[value_id % PAGE_SIZE];
+    }
+    return true;
+  }
+
+  // Set a value and return true on success.
+  bool set(uint64_t value_id, ValueArg value) {
+    Value * const page = get_page(value_id / PAGE_SIZE);
+    if (!page) {
+      return false;
+    }
+    page[value_id % PAGE_SIZE] = value;
+    return true;
+  }
+
+  // Get a value and return its address on success.
+  Value *get_pointer(uint64_t value_id) {
+    Value * const page = get_page(value_id / PAGE_SIZE);
+    if (!page) {
+      return nullptr;
+    }
+    return &page[value_id % PAGE_SIZE];
+  }
+
+  // Get a page and return its starting address on success.
+  Value *get_page(uint64_t page_id) {
+    return impl_.get_page<Value, TABLE_SIZE, SECONDARY_TABLE_SIZE>(page_id);
+  }
+
+ private:
+  Array3D impl_;
+
+  // This function is used to fill a new page with the default value.
+  static void fill_page(void *page, const void *value) {
+    Value *values = static_cast<Value *>(page);
+    for (uint64_t i = 0; i < PAGE_SIZE; ++i) {
+      std::memcpy(&values[i], value, sizeof(Value));
+    }
+  }
+};
+
 }  // namespace grnxx
 
 #endif  // GRNXX_ARRAY_IMPL_HPP

  Modified: lib/grnxx/bit_array.hpp (+13 -15)
===================================================================
--- lib/grnxx/bit_array.hpp    2013-05-28 20:32:56 +0900 (f76590e)
+++ lib/grnxx/bit_array.hpp    2013-05-29 11:45:43 +0900 (45573c2)
@@ -20,6 +20,8 @@
 
 #include "grnxx/features.hpp"
 
+#include <memory>
+
 #include "grnxx/array.hpp"
 #include "grnxx/traits.hpp"
 #include "grnxx/types.hpp"
@@ -59,19 +61,22 @@ class BitArray {
 
   // Create an array.
   bool create(Storage *storage, uint32_t storage_node_id) {
-    return impl_.create(storage, storage_node_id);
+    impl_.reset(ArrayImpl::create(storage, storage_node_id));
+    return static_cast<bool>(impl_);
   }
 
   // Create an array with the default value.
   bool create(Storage *storage, uint32_t storage_node_id,
               ValueArg default_value) {
-    return impl_.create(storage, storage_node_id,
-                        default_value ? ~Unit(0) : Unit(0));
+    impl_.reset(ArrayImpl::create(storage, storage_node_id,
+                                  default_value ? ~Unit(0) : Unit(0)));
+    return static_cast<bool>(impl_);
   }
 
   // Open an array.
   bool open(Storage *storage, uint32_t storage_node_id) {
-    return impl_.open(storage, storage_node_id);
+    impl_.reset(ArrayImpl::open(storage, storage_node_id));
+    return static_cast<bool>(impl_);
   }
 
   // Unlink an array.
@@ -102,14 +107,7 @@ class BitArray {
 
   // Return the storage node ID.
   uint32_t storage_node_id() const {
-    return impl_.storage_node_id();
-  }
-
-  // Get a value.
-  // This function throws an exception on failure.
-  Value operator[](uint64_t value_id) {
-    return (impl_[value_id / UNIT_SIZE] &
-            (Unit(1) << (value_id % UNIT_SIZE))) != 0;
+    return impl_->storage_node_id();
   }
 
   // Get a value and return true on success.
@@ -146,16 +144,16 @@ class BitArray {
 
   // Get a unit and return its address on success.
   Unit *get_unit(uint64_t unit_id) {
-    return impl_.get_value(unit_id);
+    return impl_->get_pointer(unit_id);
   }
 
   // Get a page and return its starting address on success.
   Unit *get_page(uint64_t page_id) {
-    return impl_.get_page(page_id);
+    return impl_->get_page(page_id);
   }
 
  private:
-  ArrayImpl impl_;
+  std::unique_ptr<ArrayImpl> impl_;
 };
 
 }  // namespace grnxx

  Modified: lib/grnxx/map/array_map.cpp (+15 -11)
===================================================================
--- lib/grnxx/map/array_map.cpp    2013-05-28 20:32:56 +0900 (411596a)
+++ lib/grnxx/map/array_map.cpp    2013-05-29 11:45:43 +0900 (67c92bd)
@@ -125,7 +125,7 @@ bool ArrayMap<T>::get(int64_t key_id, Key *key) {
   if (!key) {
     return true;
   }
-  return keys_.get(key_id, key);
+  return keys_->get(key_id, key);
 }
 
 template <typename T>
@@ -169,7 +169,7 @@ bool ArrayMap<T>::reset(int64_t key_id, KeyArg dest_key) {
 //    GRNXX_WARNING() << "found: dest_key = " << dest_key;
     return false;
   }
-  if (!keys_.set(key_id, Helper<T>::normalize(dest_key))) {
+  if (!keys_->set(key_id, Helper<T>::normalize(dest_key))) {
     return false;
   }
   return true;
@@ -185,7 +185,7 @@ bool ArrayMap<T>::find(KeyArg key, int64_t *key_id) {
     }
     if (bit) {
       Key stored_key;
-      if (!keys_.get(i, &stored_key)) {
+      if (!keys_->get(i, &stored_key)) {
         return false;
       }
       if (Helper<T>::equal_to(normalized_key, stored_key)) {
@@ -211,7 +211,7 @@ bool ArrayMap<T>::add(KeyArg key, int64_t *key_id) {
     }
     if (bit) {
       Key stored_key;
-      if (!keys_.get(i, &stored_key)) {
+      if (!keys_->get(i, &stored_key)) {
         return false;
       }
       if (Helper<T>::equal_to(normalized_key, stored_key)) {
@@ -226,7 +226,7 @@ bool ArrayMap<T>::add(KeyArg key, int64_t *key_id) {
       next_next_key_id = i;
     }
   }
-  if (!keys_.set(next_key_id, normalized_key) ||
+  if (!keys_->set(next_key_id, normalized_key) ||
       !bitmap_.set(next_key_id, true)) {
     return false;
   }
@@ -272,7 +272,7 @@ bool ArrayMap<T>::replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id) {
     }
     if (bit) {
       Key stored_key;
-      if (!keys_.get(i, &stored_key)) {
+      if (!keys_->get(i, &stored_key)) {
         return false;
       }
       if (Helper<T>::equal_to(normalized_src_key, stored_key)) {
@@ -288,7 +288,7 @@ bool ArrayMap<T>::replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id) {
 //    GRNXX_WARNING() << "not found: src_key = " << src_key;
     return false;
   }
-  if (!keys_.set(src_key_id, normalized_dest_key)) {
+  if (!keys_->set(src_key_id, normalized_dest_key)) {
     return false;
   }
   if (key_id) {
@@ -322,11 +322,12 @@ bool ArrayMap<T>::create_map(Storage *storage, uint32_t storage_node_id,
     return false;
   }
   header_->bitmap_storage_node_id = bitmap_.storage_node_id();
-  if (!keys_.create(storage, storage_node_id_)) {
+  keys_.reset(Array<T>::create(storage, storage_node_id_));
+  if (!keys_) {
     storage->unlink_node(storage_node_id_);
     return false;
   }
-  header_->keys_storage_node_id = keys_.storage_node_id();
+  header_->keys_storage_node_id = keys_->storage_node_id();
   return true;
 }
 
@@ -344,8 +345,11 @@ bool ArrayMap<T>::open_map(Storage *storage, uint32_t storage_node_id) {
   }
   storage_node_id_ = storage_node_id;
   header_ = static_cast<ArrayMapHeader *>(storage_node.body());
-  if (!bitmap_.open(storage, header_->bitmap_storage_node_id) ||
-      !keys_.open(storage, header_->keys_storage_node_id)) {
+  if (!bitmap_.open(storage, header_->bitmap_storage_node_id)) {
+    return false;
+  }
+  keys_.reset(Array<T>::open(storage, header_->keys_storage_node_id));
+  if (!keys_) {
     return false;
   }
   return true;

  Modified: lib/grnxx/map/array_map.hpp (+2 -2)
===================================================================
--- lib/grnxx/map/array_map.hpp    2013-05-28 20:32:56 +0900 (63d6c53)
+++ lib/grnxx/map/array_map.hpp    2013-05-29 11:45:43 +0900 (4d87bfa)
@@ -20,9 +20,9 @@
 
 #include "grnxx/features.hpp"
 
+#include "grnxx/array.hpp"
 #include "grnxx/map.hpp"
 #include "grnxx/map/bitmap.hpp"
-#include "grnxx/map/key_array.hpp"
 #include "grnxx/types.hpp"
 
 namespace grnxx {
@@ -72,7 +72,7 @@ class ArrayMap : public Map<T> {
   uint32_t storage_node_id_;
   ArrayMapHeader *header_;
   Bitmap<T> bitmap_;
-  KeyArray<T> keys_;
+  std::unique_ptr<Array<T>> keys_;
 
   bool create_map(Storage *storage, uint32_t storage_node_id,
                   const MapOptions &options);

  Modified: lib/grnxx/map/bytes_store.cpp (+24 -20)
===================================================================
--- lib/grnxx/map/bytes_store.cpp    2013-05-28 20:32:56 +0900 (52b0338)
+++ lib/grnxx/map/bytes_store.cpp    2013-05-29 11:45:43 +0900 (57159d1)
@@ -151,8 +151,8 @@ class BytesStoreImpl : public BytesStore {
   Storage *storage_;
   uint32_t storage_node_id_;
   BytesStoreHeader *header_;
-  BytesArray pages_;
-  PageHeaderArray page_headers_;
+  std::unique_ptr<BytesArray> pages_;
+  std::unique_ptr<PageHeaderArray> page_headers_;
   PeriodicClock clock_;
 
   bool create_store(Storage *storage, uint32_t storage_node_id);
@@ -239,7 +239,7 @@ bool BytesStoreImpl::get(uint64_t bytes_id, Value *bytes) {
                   << ", max_page_id = " << header_->max_page_id;
     return false;
   }
-  const uint8_t * const page = pages_.get_page(page_id);
+  const uint8_t * const page = pages_->get_page(page_id);
   if (!page) {
     return false;
   }
@@ -262,7 +262,8 @@ bool BytesStoreImpl::unset(uint64_t bytes_id) {
                   << ", max_page_id = " << header_->max_page_id;
     return false;
   }
-  BytesStorePageHeader * const page_header = page_headers_.get_value(page_id);
+  BytesStorePageHeader * const page_header =
+       page_headers_->get_pointer(page_id);
   if (!page_header) {
     return false;
   }
@@ -298,7 +299,7 @@ bool BytesStoreImpl::add(ValueArg bytes, uint64_t *bytes_id) {
   uint64_t offset = header_->next_offset;
   uint32_t size = static_cast<uint32_t>(bytes.size());
   uint32_t page_id = get_page_id(offset);
-  BytesStorePageHeader *page_header = page_headers_.get_value(page_id);
+  BytesStorePageHeader *page_header = page_headers_->get_pointer(page_id);
   if (!page_header) {
     return false;
   }
@@ -323,7 +324,7 @@ bool BytesStoreImpl::add(ValueArg bytes, uint64_t *bytes_id) {
         page_header->modified_time = clock_.now();
       }
       // Use the new ACTIVE page.
-      header_->next_offset = next_page_id * pages_.page_size();
+      header_->next_offset = next_page_id * pages_->page_size();
       offset = header_->next_offset;
       page_id = next_page_id;
       page_header = next_page_header;
@@ -332,10 +333,10 @@ bool BytesStoreImpl::add(ValueArg bytes, uint64_t *bytes_id) {
       // Use the previous ACTIVE page.
       page_header->status = BYTES_STORE_PAGE_IN_USE;
       page_header->modified_time = clock_.now();
-      header_->next_offset = next_page_id * pages_.page_size();
+      header_->next_offset = next_page_id * pages_->page_size();
     }
   }
-  uint8_t * const page = pages_.get_page(page_id);
+  uint8_t * const page = pages_->get_page(page_id);
   if (!page) {
     return false;
   }
@@ -354,7 +355,7 @@ bool BytesStoreImpl::sweep(Duration lifetime) {
     return true;
   }
   BytesStorePageHeader * const latest_empty_page_header =
-      page_headers_.get_value(header_->latest_empty_page_id);
+      page_headers_->get_pointer(header_->latest_empty_page_id);
   if (!latest_empty_page_header) {
     return false;
   }
@@ -363,7 +364,7 @@ bool BytesStoreImpl::sweep(Duration lifetime) {
     const uint32_t oldest_empty_page_id =
         latest_empty_page_header->next_page_id;
     BytesStorePageHeader * const oldest_empty_page_header =
-        page_headers_.get_value(oldest_empty_page_id);
+        page_headers_->get_pointer(oldest_empty_page_id);
     if (!oldest_empty_page_header) {
       return false;
     }
@@ -400,13 +401,14 @@ bool BytesStoreImpl::create_store(Storage *storage, uint32_t storage_node_id) {
   storage_node_id_ = storage_node.id();
   header_ = static_cast<BytesStoreHeader *>(storage_node.body());
   *header_ = BytesStoreHeader();
-  if (!pages_.create(storage, storage_node_id_) ||
-      !page_headers_.create(storage, storage_node_id_)) {
+  pages_.reset(BytesArray::create(storage, storage_node_id_));
+  page_headers_.reset(PageHeaderArray::create(storage, storage_node_id));
+  if (!pages_ || !page_headers_) {
     storage->unlink_node(storage_node_id_);
     return false;
   }
-  header_->pages_storage_node_id = pages_.storage_node_id();
-  header_->page_headers_storage_node_id = page_headers_.storage_node_id();
+  header_->pages_storage_node_id = pages_->storage_node_id();
+  header_->page_headers_storage_node_id = page_headers_->storage_node_id();
   return true;
 }
 
@@ -418,8 +420,10 @@ bool BytesStoreImpl::open_store(Storage *storage, uint32_t storage_node_id) {
   }
   storage_node_id_ = storage_node.id();
   header_ = static_cast<BytesStoreHeader *>(storage_node.body());
-  if (!pages_.open(storage, header_->pages_storage_node_id) ||
-      !page_headers_.open(storage, header_->page_headers_storage_node_id)) {
+  pages_.reset(BytesArray::open(storage, header_->pages_storage_node_id));
+  page_headers_.reset(
+      PageHeaderArray::open(storage, header_->page_headers_storage_node_id));
+  if (!pages_ || !page_headers_) {
     return false;
   }
   return true;
@@ -432,7 +436,7 @@ bool BytesStoreImpl::reserve_active_page(uint32_t *page_id,
   if (header_->latest_idle_page_id != BYTES_STORE_INVALID_PAGE_ID) {
     // Use the oldest IDLE page.
     latest_idle_page_header =
-        page_headers_.get_value(header_->latest_idle_page_id);
+        page_headers_->get_pointer(header_->latest_idle_page_id);
     if (!latest_idle_page_header) {
       return false;
     }
@@ -442,7 +446,7 @@ bool BytesStoreImpl::reserve_active_page(uint32_t *page_id,
     next_page_id = header_->max_page_id + 1;
   }
   BytesStorePageHeader * const next_page_header =
-      page_headers_.get_value(next_page_id);
+      page_headers_->get_pointer(next_page_id);
   if (!next_page_header) {
     return false;
   }
@@ -467,7 +471,7 @@ bool BytesStoreImpl::make_page_empty(uint32_t page_id,
   BytesStorePageHeader *latest_empty_page_header = nullptr;
   if (header_->latest_empty_page_id != BYTES_STORE_INVALID_PAGE_ID) {
     latest_empty_page_header =
-        page_headers_.get_value(header_->latest_empty_page_id);
+        page_headers_->get_pointer(header_->latest_empty_page_id);
     if (!latest_empty_page_header) {
       return false;
     }
@@ -489,7 +493,7 @@ bool BytesStoreImpl::make_page_idle(uint32_t page_id,
   BytesStorePageHeader *latest_idle_page_header = nullptr;
   if (header_->latest_idle_page_id != BYTES_STORE_INVALID_PAGE_ID) {
     BytesStorePageHeader * const latest_idle_page_header =
-        page_headers_.get_value(header_->latest_idle_page_id);
+        page_headers_->get_pointer(header_->latest_idle_page_id);
     if (!latest_idle_page_header) {
       return false;
     }

  Modified: test/test_array.cpp (+27 -27)
===================================================================
--- test/test_array.cpp    2013-05-28 20:32:56 +0900 (9d47932)
+++ test/test_array.cpp    2013-05-29 11:45:43 +0900 (5ad4d61)
@@ -32,50 +32,50 @@ void test_array() {
 
   // Create an anonymous Storage.
   std::unique_ptr<grnxx::Storage> storage(grnxx::Storage::create(nullptr));
-  grnxx::Array<int, PAGE_SIZE, TABLE_SIZE, SECONDARY_TABLE_SIZE> array;
+  std::unique_ptr<grnxx::Array<int, PAGE_SIZE, TABLE_SIZE,
+                               SECONDARY_TABLE_SIZE>> array;
   uint32_t storage_node_id;
 
   // Create an Array and test its member functions.
-  assert(array.create(storage.get(), grnxx::STORAGE_ROOT_NODE_ID));
+  array.reset(array->create(storage.get(), grnxx::STORAGE_ROOT_NODE_ID));
   assert(array);
-  assert(array.page_size() == PAGE_SIZE);
-  assert(array.table_size() == TABLE_SIZE);
-  assert(array.secondary_table_size() == SECONDARY_TABLE_SIZE);
-  assert(array.size() == (PAGE_SIZE * TABLE_SIZE * SECONDARY_TABLE_SIZE));
-  storage_node_id = array.storage_node_id();
-
-  for (std::uint64_t i = 0; i < array.size(); ++i) {
-    assert(array.set(i, static_cast<int>(i)));
+  assert(array->page_size() == PAGE_SIZE);
+  assert(array->table_size() == TABLE_SIZE);
+  assert(array->secondary_table_size() == SECONDARY_TABLE_SIZE);
+  assert(array->size() == (PAGE_SIZE * TABLE_SIZE * SECONDARY_TABLE_SIZE));
+  storage_node_id = array->storage_node_id();
+
+  for (std::uint64_t i = 0; i < array->size(); ++i) {
+    assert(array->set(i, static_cast<int>(i)));
   }
-  for (std::uint64_t i = 0; i < array.size(); ++i) {
+  for (std::uint64_t i = 0; i < array->size(); ++i) {
     int value;
-    assert(array.get(i, &value));
+    assert(array->get(i, &value));
     assert(value == static_cast<int>(i));
   }
-  for (std::uint64_t i = 0; i < (array.size() / array.page_size()); ++i) {
-    assert(array.get_page(i));
+  for (std::uint64_t i = 0; i < (array->size() / array->page_size()); ++i) {
+    assert(array->get_page(i));
   }
 
   // Open the Array.
-  assert(array.open(storage.get(), storage_node_id));
-  for (std::uint64_t i = 0; i < array.size(); ++i) {
+  assert(array->open(storage.get(), storage_node_id));
+  for (std::uint64_t i = 0; i < array->size(); ++i) {
     int value;
-    assert(array.get(i, &value));
+    assert(array->get(i, &value));
     assert(value == static_cast<int>(i));
   }
 
   // Create an Array with default value.
-  assert(array.create(storage.get(), grnxx::STORAGE_ROOT_NODE_ID, 1));
+  array.reset(array->create(storage.get(), grnxx::STORAGE_ROOT_NODE_ID, 123));
   assert(array);
-  for (std::uint64_t i = 0; i < array.size(); ++i) {
-    assert(array[i] == 1);
-    array[i] = static_cast<int>(i);
-  }
-  for (std::uint64_t i = 0; i < array.size(); ++i) {
-    assert(array[i] == static_cast<int>(i));
-  }
-  for (std::uint64_t i = 0; i < array.size(); ++i) {
-    assert(&array[i] == array.get_value(i));
+  for (std::uint64_t i = 0; i < array->size(); ++i) {
+    int value;
+    assert(array->get(i, &value));
+    assert(value == 123);
+
+    int * const pointer = array->get_pointer(i);
+    assert(pointer);
+    assert(*pointer == 123);
   }
 }
 

  Modified: test/test_bit_array.cpp (+6 -6)
===================================================================
--- test/test_bit_array.cpp    2013-05-28 20:32:56 +0900 (434557e)
+++ test/test_bit_array.cpp    2013-05-29 11:45:43 +0900 (e7689f1)
@@ -67,10 +67,6 @@ void test_bit_array() {
     assert(array.get(i, &stored_bit));
     assert(stored_bit == expected_bit);
   }
-  for (std::uint64_t i = 0; i < array.size(); ++i) {
-    const bool expected_bit = (units[i / 64] >> (i % 64)) & 1;
-    assert(array[i] == expected_bit);
-  }
   for (std::uint64_t i = 0; i < (array.size() / array.unit_size()); ++i) {
     const Unit * const unit = array.get_unit(i);
     assert(unit);
@@ -93,12 +89,16 @@ void test_bit_array() {
   assert(array.create(storage.get(), grnxx::STORAGE_ROOT_NODE_ID, false));
   assert(array);
   for (std::uint64_t i = 0; i < array.size(); ++i) {
-    assert(!array[i]);
+    bool bit;
+    assert(array.get(i, &bit));
+    assert(!bit);
   }
   assert(array.create(storage.get(), grnxx::STORAGE_ROOT_NODE_ID, true));
   assert(array);
   for (std::uint64_t i = 0; i < array.size(); ++i) {
-    assert(array[i]);
+    bool bit;
+    assert(array.get(i, &bit));
+    assert(bit);
   }
 }
 
-------------- next part --------------
HTML����������������������������...
Télécharger 



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