Use malloc instead of std::vector Refs/for/tizen
authorHwankyu Jhun <h.jhun@samsung.com>
Thu, 22 Sep 2022 01:36:53 +0000 (01:36 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Fri, 23 Sep 2022 02:06:04 +0000 (02:06 +0000)
To improve the performance of the parcel creation, the data_ variable of
the parcel implementation is changed to uint8_t*. And, the DataCapacitor
class is added to manage the allocated memory.
While destroying the parcel instance, the allocated memory is set to
the DataCapacitor object.

Change-Id: Ia88815746d646ce089de802d89017c96cbc6b30d
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
parcel/api/parcel.h
parcel/parcel.cc
parcel/parcel.hh
parcel/parcel_implementation.hh
parcel/stub.cc
tests/parcel_unittests/test_parcel_cpp.cc

index 640b3b179d174f8791696f03dedb92e31282194f..10dbaba807e602103571de043645bddaed1a85c6 100644 (file)
@@ -529,6 +529,32 @@ int parcel_get_raw(parcel_h parcel, void **raw, uint32_t *size);
  */
 int parcel_set_byte_order(parcel_h parcle, bool big_endian);
 
+/**
+ * @brief Gets the size of the data capacity of the parcel handle.
+ * @since_tizen 7.0
+ * @param[in] parcel The parcel handle
+ * @param[out] size The size of the data capacity
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #PARCEL_ERROR_NONE Successful
+ * @retval #PARCEL_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int parcel_get_data_capacity(parcel_h parcel, size_t *size);
+
+/**
+ * @brief Sets the size of the data capacity of the parcel handle.
+ * @since_tizen 7.0
+ * @remarks The raw data will be reallocated using the given size.
+ * @param[in] parcel The parcel handle
+ * @param[in] size The size of the data capacity
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #PARCEL_ERROR_NONE Successful
+ * @retval #PARCEL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #PARCEL_ERROR_OUT_OF_MEMORY
+ */
+int parcel_set_data_capacity(parcel_h parcel, size_t size);
+
 #ifdef __cplusplus
 }
 #endif
index 2c3e13f0ce4cbe33bafb1cdc7755e4431cdc5ba0..1fd9a0334b7cd6ae217c244553c88f35828684e5 100644 (file)
@@ -16,6 +16,9 @@
 
 #include <glib.h>
 
+#include <exception>
+#include <mutex>
+
 #include "parcel/common.hh"
 #include "parcel/log_private.hh"
 #include "parcel/parcel.hh"
 #include "parcel/parcelable.hh"
 
 namespace tizen_base {
+namespace {
+
+constexpr const size_t kDataCapacity = 128;
+
+class DataCapacitor {
+ public:
+  DataCapacitor() {
+    data_ = static_cast<uint8_t*>(malloc(data_capacity_));
+    if (data_ == nullptr)
+      data_capacity_ = 0;
+  }
+
+  ~DataCapacitor() {
+    free(data_);
+  }
+
+  void Set(uint8_t* data, size_t data_capacity) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    free(data_);
+    data_ = data;
+    data_capacity_ = data_capacity;
+  }
 
-Parcel::Impl::Impl(Parcel* parent, bool big_endian)
-    : parent_(parent), big_endian_(big_endian) {
+  uint8_t* Detach(size_t* data_capacity) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    uint8_t* data = data_;
+    *data_capacity = data_capacity_;
+    data_ = nullptr;
+    data_capacity_ = 0;
+    return data;
+  }
+
+ private:
+  uint8_t* data_;
+  size_t data_capacity_ = kDataCapacity;
+  std::recursive_mutex mutex_;
+};
+
+DataCapacitor capacitor;
+
+}  // namespace
+
+Parcel::Impl::Impl(Parcel* parent, size_t data_capacity, bool big_endian)
+    : parent_(parent), data_capacity_(data_capacity), big_endian_(big_endian) {
+  size_t capacity = 0;
+  auto* data = capacitor.Detach(&capacity);
+  if (data != nullptr) {
+    if (data_capacity_ > capacity) {
+      data_ = static_cast<uint8_t*>(realloc(data, data_capacity_));
+      if (data_ == nullptr) {
+        free(data);
+        throw std::bad_alloc();
+      }
+    } else {
+      data_capacity_ = capacity;
+      data_ = data;
+    }
+  } else {
+    data_ = static_cast<uint8_t*>(malloc(data_capacity_));
+    if (data_ == nullptr)
+      throw std::bad_alloc();
+  }
 }
 
-Parcel::Impl::~Impl() = default;
+Parcel::Impl::~Impl() {
+  capacitor.Set(data_, data_capacity_);
+}
 
 void Parcel::Impl::Write(const void* buf, uint32_t size) {
-  auto* p = reinterpret_cast<const uint8_t*>(buf);
-  data_.insert(data_.end(), p, p + size);
+  if (data_size_ + size > data_capacity_) {
+    size_t new_size = (data_capacity_ + size) * 3 / 2;
+    uint8_t* data = static_cast<uint8_t*>(realloc(data_, new_size));
+    if (data == nullptr)
+      throw std::bad_alloc();
+
+    data_ = data;
+    data_capacity_ = new_size;
+  }
+
+  memcpy(data_ + data_size_, buf, size);
+  data_size_ += size;
 }
 
 int Parcel::Impl::Read(void* buf, uint32_t size) {
-  if (data_.size() == 0)
+  if (data_size_ == 0)
     return TIZEN_ERROR_NO_DATA;
 
-  if (reader_ + size > data_.size())
+  if (reader_ + size > data_size_)
     return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
 
-  auto* p = reinterpret_cast<uint8_t*>(buf);
-  std::copy(&data_[reader_], &data_[reader_] + size, p);
+  memcpy(buf, data_ + reader_, size);
   reader_ += size;
   set_last_result(TIZEN_ERROR_NONE);
   return TIZEN_ERROR_NONE;
 }
 
 const std::vector<uint8_t>& Parcel::Impl::GetRaw() {
-  return data_;
+  raw_.clear();
+  raw_.assign(data_, data_ + data_size_);
+  return raw_;
 }
 
 void Parcel::Impl::ResetReader() {
@@ -58,7 +133,7 @@ void Parcel::Impl::ResetReader() {
 }
 
 void Parcel::Impl::Clear() {
-  data_.clear();
+  data_size_ = 0;
   reader_ = 0;
 }
 
@@ -68,7 +143,7 @@ void Parcel::Impl::Reset(const void* buf, uint32_t size) {
 }
 
 bool Parcel::Impl::IsEmpty() {
-  return data_.size() == 0;
+  return data_size_ == 0;
 }
 
 void Parcel::Impl::WriteSize(uint32_t size) {
@@ -80,20 +155,28 @@ void Parcel::Impl::WriteSize(uint32_t size) {
 
 template <typename T>
 void Parcel::Impl::Write(T d) {
+  if (data_size_ + sizeof(T) > data_capacity_) {
+    size_t new_size = (data_capacity_ + sizeof(T)) * 3 / 2;
+    uint8_t* data = static_cast<uint8_t*>(realloc(data_, new_size));
+    if (data == nullptr)
+      throw std::bad_alloc();
+
+    data_ = data;
+    data_capacity_ = new_size;
+  }
+
   auto* p = reinterpret_cast<uint8_t*>(&d);
-  data_.insert(data_.end(), p, p + sizeof(T));
+  memcpy(data_ + data_size_, p, sizeof(T));
+  data_size_ += sizeof(T);
 }
 
 int Parcel::Impl::ReadSize(uint32_t* size) {
-  if (data_.size() == 0)
+  if (data_size_ == 0)
     return TIZEN_ERROR_NO_DATA;
 
-  if (reader_ + sizeof(uint32_t) > data_.size())
-    return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
-
-  auto* p = reinterpret_cast<uint8_t*>(size);
-  std::copy(&data_[reader_], &data_[reader_] + sizeof(uint32_t), p);
-  reader_ += sizeof(uint32_t);
+  int ret = Read<uint32_t>(size);
+  if (ret != TIZEN_ERROR_NONE)
+    return ret;
 
   if (IsBigEndian())
     *size = GUINT32_FROM_BE(*size);
@@ -104,11 +187,11 @@ int Parcel::Impl::ReadSize(uint32_t* size) {
 template <typename T>
 int Parcel::Impl::Read(T* d) {
   uint32_t size = sizeof(T);
-  if (reader_ + size > data_.size())
+  if (reader_ + size > data_size_)
     return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
 
   auto* p = reinterpret_cast<uint8_t*>(d);
-  std::copy(&data_[reader_], &data_[reader_] + size, p);
+  memcpy(p, data_ + reader_, size);
   reader_ += size;
   return TIZEN_ERROR_NONE;
 }
@@ -117,45 +200,113 @@ void Parcel::Impl::SetByteOrder(bool big_endian) {
   big_endian_ = big_endian;
 }
 
-bool Parcel::Impl::IsBigEndian() {
+bool Parcel::Impl::IsBigEndian() const {
   return big_endian_;
 }
 
-Parcel::Parcel(bool big_endian) : impl_(new Impl(this, big_endian)) {
+uint8_t* Parcel::Impl::GetData() const {
+  return data_;
+}
+
+size_t Parcel::Impl::GetDataSize() const {
+  return data_size_;
+}
+
+size_t Parcel::Impl::GetDataCapacity() const {
+  return data_capacity_;
+}
+
+void Parcel::Impl::SetDataCapacity(size_t size) {
+  uint8_t* data = static_cast<uint8_t*>(realloc(data_, size));
+  if (data == nullptr)
+    throw std::bad_alloc();
+
+  data_ = data;
+  data_capacity_ = size;
+}
+
+Parcel::Parcel(bool big_endian)
+    : impl_(new Impl(this, kDataCapacity, big_endian)) {
 }
 
 Parcel::Parcel(const void* buf, uint32_t size, bool big_endian)
-    : impl_(new Impl(this, big_endian)) {
+    : impl_(new Impl(this, size, big_endian)) {
   impl_->Write(buf, size);
 }
 
 Parcel::~Parcel() = default;
 
 Parcel::Parcel(const Parcel& p)
-  : impl_(new Impl(this)) {
+  : impl_(new Impl(this, kDataCapacity)) {
   impl_->big_endian_ = p.impl_->big_endian_;
-  impl_->data_ = p.impl_->data_;
+  impl_->data_capacity_ = p.impl_->data_capacity_;
+  impl_->data_size_ = p.impl_->data_size_;
+
+  uint8_t* data = static_cast<uint8_t*>(
+      realloc(impl_->data_, impl_->data_capacity_));
+  if (data == nullptr)
+    throw std::bad_alloc();
+
+  impl_->data_ = data;
+  memcpy(impl_->data_, p.impl_->data_, impl_->data_size_);
+
   impl_->reader_ = p.impl_->reader_;
 }
 
 Parcel& Parcel::operator = (const Parcel& p) {
   if (this != &p) {
     impl_->big_endian_ = p.impl_->big_endian_;
-    impl_->data_ = p.impl_->data_;
+    impl_->data_capacity_ = p.impl_->data_capacity_;
+    impl_->data_size_ = p.impl_->data_size_;
+
+    uint8_t* data = static_cast<uint8_t*>(
+        realloc(impl_->data_, impl_->data_capacity_));
+    if (data == nullptr)
+      throw std::bad_alloc();
+
+    impl_->data_ = data;
+    memcpy(impl_->data_, p.impl_->data_, impl_->data_size_);
+
     impl_->reader_ = p.impl_->reader_;
   }
   return *this;
 }
 
 Parcel::Parcel(Parcel&& p) noexcept {
-  impl_ = std::move(p.impl_);
-  impl_->parent_ = this;
+  impl_->big_endian_ = p.impl_->big_endian_;
+
+  impl_->data_size_ = p.impl_->data_size_;
+  p.impl_->data_size_ = 0;
+
+  uint8_t* data = impl_->data_;
+  size_t data_capacity = impl_->data_capacity_;
+
+  impl_->data_ = p.impl_->data_;
+  impl_->data_capacity_ = p.impl_->data_capacity_;
+
+  p.impl_->data_ = data;
+  p.impl_->data_capacity_ = data_capacity;
+
+  impl_->reader_ = p.impl_->reader_;
+  p.impl_->reader_ = 0;
 }
 
 Parcel& Parcel::operator = (Parcel&& p) noexcept {
   if (this != &p) {
     impl_->big_endian_ = p.impl_->big_endian_;
-    impl_->data_ = std::move(p.impl_->data_);
+
+    impl_->data_size_ = p.impl_->data_size_;
+    p.impl_->data_size_ = 0;
+
+    uint8_t* data = impl_->data_;
+    size_t data_capacity = impl_->data_capacity_;
+
+    impl_->data_ = p.impl_->data_;
+    impl_->data_capacity_ = p.impl_->data_capacity_;
+
+    p.impl_->data_ = data;
+    p.impl_->data_capacity_ = data_capacity;
+
     impl_->reader_ = p.impl_->reader_;
     p.impl_->reader_ = 0;
   }
@@ -394,4 +545,20 @@ void Parcel::SetByteOrder(bool big_endian) {
   impl_->SetByteOrder(big_endian);
 }
 
+uint8_t* Parcel::GetData() const {
+  return impl_->GetData();
+}
+
+size_t Parcel::GetDataSize() const {
+  return impl_->GetDataSize();
+}
+
+size_t Parcel::GetDataCapacity() const {
+  return impl_->GetDataCapacity();
+}
+
+void Parcel::SetDataCapacity(size_t size) {
+  impl_->SetDataCapacity(size);
+}
+
 }  // namespace tizen_base
index 87af7d7c9fe8ff7e8477a797cb8eff06a0f5ab7e..2ea3f38d1a19c32e22b27ff0d5f15e5fd31da748 100644 (file)
@@ -378,6 +378,34 @@ class EXPORT Parcel final {
    */
   void SetByteOrder(bool big_endian);
 
+  /**
+   * @brief Gets the raw data of the parcel.
+   * @since_tizen 7.0
+   * @return The raw data
+   */
+  uint8_t* GetData() const;
+
+  /**
+   * @breif Gets the size of the raw data of the parcel.
+   * @since_tizen 7.0
+   * @return The size of the raw data
+   */
+  size_t GetDataSize() const;
+
+  /**
+   * @brief Gets the size of the data capacity of the parcel.
+   * @since_tizen 7.0
+   * @return The size of the data capacity
+   */
+  size_t GetDataCapacity() const;
+
+  /**
+   * @breif Sets the size of the data capacity of the parcel.
+   * @since_tizen 7.0
+   * @param[in] size The size of the data capcity
+   */
+  void SetDataCapacity(size_t size);
+
  private:
   class Impl;
   std::unique_ptr<Impl> impl_;
index ed6c62fcf95c10ad0d787c241af8be3a394b9cec..502bc79d24209a45962bc2a90354ac2d21a3f25d 100644 (file)
@@ -45,17 +45,24 @@ class Parcel::Impl {
   int Read(T* d);
 
   void SetByteOrder(bool big_endian);
-  bool IsBigEndian();
+  bool IsBigEndian() const;
+  uint8_t* GetData() const;
+  size_t GetDataSize() const;
+  size_t GetDataCapacity() const;
+  void SetDataCapacity(size_t size);
 
  private:
   friend class Parcel;
-  explicit Impl(Parcel* parent, bool big_endian = false);
+  explicit Impl(Parcel* parent, size_t data_capacity, bool big_endian = false);
 
  private:
   Parcel* parent_;
+  size_t data_capacity_;
   bool big_endian_;
-  std::vector<uint8_t> data_;
+  size_t data_size_ = 0;
+  uint8_t* data_ = nullptr;
   uint64_t reader_ = 0;
+  std::vector<uint8_t> raw_;
 };
 
 }  // naemspace tizen_base
index ce625842c27a7757fd463e78bf4f25d0226a381e..f6b6299fcc7322b5448bd42f298c409f8eb156c7 100644 (file)
@@ -15,6 +15,9 @@
  */
 
 #include "parcel/api/parcel.h"
+
+#include <exception>
+
 #include "parcel/common.hh"
 #include "parcel/log_private.hh"
 #include "parcel/parcel.hh"
@@ -386,9 +389,8 @@ extern "C" EXPORT int parcel_get_raw(parcel_h parcel, void** raw,
   }
 
   auto* h = static_cast<Parcel*>(parcel);
-  auto& raw_data = h->GetRaw();
-  *raw = reinterpret_cast<void*>(const_cast<uint8_t*>(&raw_data[0]));
-  *size = raw_data.size();
+  *raw = reinterpret_cast<void*>(h->GetData());
+  *size = h->GetDataSize();
   return PARCEL_ERROR_NONE;
 }
 
@@ -403,3 +405,33 @@ extern "C" EXPORT int parcel_set_byte_order(parcel_h parcel,
   h->SetByteOrder(big_endian);
   return PARCEL_ERROR_NONE;
 }
+
+extern "C" EXPORT int parcel_get_data_capacity(parcel_h parcel,
+    size_t* size) {
+  if (parcel == nullptr || size == nullptr) {
+    _E("Invalid parameter");
+    return PARCEL_ERROR_INVALID_PARAMETER;
+  }
+
+  auto* h = static_cast<Parcel*>(parcel);
+  *size = h->GetDataCapacity();
+  return PARCEL_ERROR_NONE;
+}
+
+extern "C" EXPORT int parcel_set_data_capacity(parcel_h parcel,
+    size_t size) {
+  if (parcel == nullptr || size == 0) {
+    _E("Invalid parameter");
+    return PARCEL_ERROR_INVALID_PARAMETER;
+  }
+
+  auto* h = static_cast<Parcel*>(parcel);
+  try {
+    h->SetDataCapacity(size);
+  } catch (const std::bad_alloc& e) {
+    _E("Exception occurs. error(%s)", e.what());
+    return PARCEL_ERROR_OUT_OF_MEMORY;
+  }
+
+  return PARCEL_ERROR_NONE;
+}
index ff52fb11e9db6357f7b52c1b912ac1003058ca84..9236c94ed72dc97180ee04004f911f71fc0794fc 100644 (file)
@@ -187,7 +187,7 @@ TEST_F(ParcelCppTest, WriteCString_AND_ReadCString) {
 TEST_F(ParcelCppTest, GetRaw) {
   GetHandle().WriteInt32(0);
   auto& raw = GetHandle().GetRaw();
-  ASSERT_EQ(raw.size(), sizeof(int32_t));
+  ASSERT_EQ(raw.size(), sizeof(int));
 }
 
 TEST_F(ParcelCppTest, ResetReader) {