[Groonga-commit] groonga/grnxx at 06d7f3f [master] Update Array to use realloc() for trivial types. (#123)

アーカイブの一覧に戻る

susumu.yata null+****@clear*****
Mon Dec 1 17:34:49 JST 2014


susumu.yata	2014-12-01 17:34:49 +0900 (Mon, 01 Dec 2014)

  New Revision: 06d7f3f7acf964772ee0098dd75dcd5e9516d0c1
  https://github.com/groonga/grnxx/commit/06d7f3f7acf964772ee0098dd75dcd5e9516d0c1

  Message:
    Update Array to use realloc() for trivial types. (#123)

  Modified files:
    include/grnxx/array.hpp

  Modified: include/grnxx/array.hpp (+245 -2)
===================================================================
--- include/grnxx/array.hpp    2014-12-01 15:33:00 +0900 (abd51a9)
+++ include/grnxx/array.hpp    2014-12-01 17:34:49 +0900 (0d217c9)
@@ -2,7 +2,9 @@
 #define GRNXX_ARRAY_HPP
 
 #include <cstdlib>
+#include <cstring>
 #include <new>
+#include <type_traits>
 #include <utility>
 
 namespace grnxx {
@@ -137,8 +139,12 @@ class ArrayRef {
   size_t size_;
 };
 
+template <typename T, bool IS_TRIVIAL = std::is_trivial<T>::value>
+class Array;
+
+// The Array implementation for non-trivial types.
 template <typename T>
-class Array {
+class Array<T, false> {
  public:
   using Value = T;
 
@@ -355,7 +361,7 @@ class Array {
     size_t new_buffer_size = sizeof(Value) * new_capacity;
     Value *new_buffer = static_cast<Value *>(std::malloc(new_buffer_size));
     if (!new_buffer) {
-      throw "Failed";  // TODO
+      throw "Memory allocation failed";  // TODO
     }
     for (size_t i = 0; i < size_; ++i) {
       new (&new_buffer[i]) Value(std::move(buffer()[i]));
@@ -366,6 +372,243 @@ class Array {
   }
 };
 
+// The Array implementation for trivial types.
+template <typename T>
+class Array<T, true> {
+ public:
+  using Value = T;
+
+  Array() : buffer_(nullptr), size_(0), capacity_(0) {}
+  ~Array() {
+    std::free(buffer_);
+  }
+
+  Array(const Array &) = delete;
+  Array &operator=(const Array &) & = delete;
+
+  // Move the ownership of an array.
+  Array(Array &&array)
+      : buffer_(array.buffer_),
+        size_(array.size_),
+        capacity_(array.capacity_) {
+    array.buffer_ = nullptr;
+    array.size_ = 0;
+    array.capacity_ = 0;
+  }
+  // Move the ownership of an array.
+  Array &operator=(Array &&array) & {
+    std::free(buffer_);
+    buffer_ = array.buffer_;
+    size_ = array.size_;
+    capacity_ = array.capacity_;
+    array.buffer_ = nullptr;
+    array.size_ = 0;
+    array.capacity_ = 0;
+    return *this;
+  }
+
+  // Create a reference to "this".
+  operator ArrayCRef<Value>() const {
+    return cref();
+  }
+
+  // Create a reference to a part of "this".
+  ArrayCRef<Value> cref(size_t offset = 0) const {
+    return ArrayCRef<Value>(data() + offset, size_ - offset);
+  }
+  // Create a reference to a part of "this".
+  ArrayCRef<Value> cref(size_t offset, size_t size) const {
+    return ArrayCRef<Value>(data() + offset, size);
+  }
+
+  // Create a reference to a part of "this".
+  ArrayRef<Value> ref(size_t offset = 0) {
+    return ArrayRef<Value>(buffer() + offset, size_ - offset);
+  }
+  // Create a reference to a part of "this".
+  ArrayRef<Value> ref(size_t offset, size_t size) {
+    return ArrayRef<Value>(buffer() + offset, size);
+  }
+
+  // Return a reference to the "i"-th value.
+  const Value &get(size_t i) const {
+    return data()[i];
+  }
+  // Set the "i"-th value.
+  void set(size_t i, const Value &value) {
+    buffer()[i] = value;
+  }
+  // Set the "i"-th value.
+  void set(size_t i, Value &&value) {
+    buffer()[i] = std::move(value);
+  }
+
+  // Return a reference to the "i"-th value.
+  Value &operator[](size_t i) {
+    return buffer()[i];
+  }
+  // Return a reference to the "i"-th value.
+  const Value &operator[](size_t i) const {
+    return data()[i];
+  }
+
+  // Return a reference to the first value.
+  Value &front() {
+    return *buffer();
+  }
+  // Return a reference to the first value.
+  const Value &front() const {
+    return *data();
+  }
+
+  // Return a reference to the last value.
+  Value &back() {
+    return buffer()[size_ - 1];
+  }
+  // Return a reference to the last value.
+  const Value &back() const {
+    return data()[size_ - 1];
+  }
+
+  // Return a pointer to the buffer.
+  Value *buffer() {
+    return static_cast<Value *>(buffer_);
+  }
+  // Return a pointer to the contents.
+  const Value *data() const {
+    return static_cast<const Value *>(buffer_);
+  }
+
+  // Return whether the array is empty or not.
+  bool is_empty() const {
+    return size_ == 0;
+  }
+  // Return the number of values.
+  size_t size() const {
+    return size_;
+  }
+  // Return the number of values can be stored in the buffer.
+  size_t capacity() const {
+    return capacity_;
+  }
+
+  // Reserve memory for at least "new_size" values.
+  //
+  // On failure, throws an exception.
+  void reserve(size_t new_size) {
+    if (new_size > capacity_) {
+      resize_buffer(new_size);
+    }
+  }
+
+  // Resize "this".
+  //
+  // On failure, throws an exception.
+  void resize(size_t new_size) {
+    if (new_size > capacity_) {
+      resize_buffer(new_size);
+    }
+    for (size_t i = new_size; i < size_; ++i) {
+      buffer()[i].~Value();
+    }
+    for (size_t i = size_; i < new_size; ++i) {
+      new (&buffer()[i]) Value;
+    }
+    size_ = new_size;
+  }
+  // Resize "this" and fill the new values with "value".
+  //
+  // On failure, throws an exception.
+  void resize(size_t new_size, const Value &value) {
+    if (new_size > capacity_) {
+      resize_buffer(new_size);
+    }
+    for (size_t i = new_size; i < size_; ++i) {
+      buffer()[i].~Value();
+    }
+    for (size_t i = size_; i < new_size; ++i) {
+      new (&buffer()[i]) Value(value);
+    }
+    size_ = new_size;
+  }
+
+  // Clear the contents.
+  void clear() {
+    for (size_t i = 0; i < size_; ++i) {
+      buffer()[i].~Value();
+    }
+    size_ = 0;
+  }
+
+  // Remove the "i"-th value.
+  void erase(size_t i) {
+    for (size_t j = i + 1; j < size_; ++j) {
+      buffer()[j - 1] = std::move(buffer()[j]);
+    }
+    buffer()[size_ - 1].~Value();
+    --size_;
+  }
+
+  // Append "value" to the end.
+  //
+  // On failure, throws an exception.
+  void push_back(const Value &value) {
+    if (size_ == capacity_) {
+      resize_buffer(size_ + 1);
+    }
+    new (&buffer()[size_]) Value(value);
+    ++size_;
+  }
+  // Append "value" to the end.
+  //
+  // On failure, throws an exception.
+  void push_back(Value &&value) {
+    if (size_ == capacity_) {
+      resize_buffer(size_ + 1);
+    }
+    new (&buffer()[size_]) Value(std::move(value));
+    ++size_;
+  }
+  // Remove the last value.
+  void pop_back() {
+    buffer()[size_ - 1].~Value();
+    --size_;
+  }
+
+ private:
+  void *buffer_;
+  size_t size_;
+  size_t capacity_;
+
+  // Resize the buffer for at least "new_size" values.
+  //
+  // Assumes that "new_size" is greater than "capacity_".
+  void resize_buffer(size_t new_size) {
+    if (capacity_ != 0) {
+      size_t new_capacity = capacity_ * 2;
+      if (new_size > new_capacity) {
+        new_capacity = new_size;
+      }
+      size_t new_buffer_size = sizeof(Value) * new_capacity;
+      Value *new_buffer =
+          static_cast<Value *>(std::realloc(buffer_, new_buffer_size));
+      if (!new_buffer) {
+        throw "Memory allocation failed";  // TODO
+      }
+      buffer_ = new_buffer;
+      capacity_ = new_capacity;
+    } else {
+      size_t new_buffer_size = sizeof(Value) * new_size;
+      Value *new_buffer = static_cast<Value *>(std::malloc(new_buffer_size));
+      if (!new_buffer) {
+        throw "Memory allocation failed";  // TODO
+      }
+      buffer_ = new_buffer;
+      capacity_ = new_size;
+    }
+  }
+};
+
 }  // namespace grnxx
 
 #endif  // GRNXX_ARRAY_HPP
-------------- next part --------------
HTML����������������������������...
ダウンロード 



More information about the Groonga-commit mailing list
アーカイブの一覧に戻る