#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() {
}
void Parcel::Impl::Clear() {
- data_.clear();
+ data_size_ = 0;
reader_ = 0;
}
}
bool Parcel::Impl::IsEmpty() {
- return data_.size() == 0;
+ return data_size_ == 0;
}
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);
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;
}
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;
}
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