#pragma once /** @file @brief scoped array and aligned array @author MITSUNARI Shigeo(@herumi) */ #include #include #ifdef _WIN32 #include #else #include #endif #include namespace cybozu { inline void *AlignedMalloc(size_t size, size_t alignment) { #ifdef _WIN32 return _aligned_malloc(size, alignment); #else void *p; int ret = posix_memalign(&p, alignment, size); return (ret == 0) ? p : 0; #endif } inline void AlignedFree(void *p) { #ifdef _WIN32 if (p == 0) return; _aligned_free(p); #else free(p); #endif } template class ScopedArray { T *p_; size_t size_; ScopedArray(const ScopedArray&); void operator=(const ScopedArray&); public: explicit ScopedArray(size_t size) : p_(new T[size]) , size_(size) { } ~ScopedArray() { delete[] p_; } T& operator[](size_t idx) CYBOZU_NOEXCEPT { return p_[idx]; } const T& operator[](size_t idx) const CYBOZU_NOEXCEPT { return p_[idx]; } size_t size() const CYBOZU_NOEXCEPT { return size_; } bool empty() const CYBOZU_NOEXCEPT { return size_ == 0; } T* begin() CYBOZU_NOEXCEPT { return p_; } T* end() CYBOZU_NOEXCEPT { return p_ + size_; } const T* begin() const CYBOZU_NOEXCEPT { return p_; } const T* end() const CYBOZU_NOEXCEPT { return p_ + size_; } T* data() CYBOZU_NOEXCEPT { return p_; } const T* data() const CYBOZU_NOEXCEPT { return p_; } }; /** T must be POD type 16byte aligment array */ template class AlignedArray { T *p_; size_t size_; size_t allocSize_; T *alloc(size_t size) const { T *p = static_cast(AlignedMalloc(size * sizeof(T), N)); if (p == 0) throw std::bad_alloc(); return p; } void copy(T *dst, const T *src, size_t n) const { for (size_t i = 0; i < n; i++) dst[i] = src[i]; } void setZero(T *p, size_t n) const { for (size_t i = 0; i < n; i++) p[i] = 0; } /* alloc allocN and copy [p, p + copyN) to new p_ don't modify size_ */ void allocCopy(size_t allocN, const T *p, size_t copyN) { T *q = alloc(allocN); copy(q, p, copyN); AlignedFree(p_); p_ = q; allocSize_ = allocN; } public: /* don't clear buffer with zero if doClear is false */ explicit AlignedArray(size_t size = 0, bool doClear = defaultDoClear) : p_(0) , size_(0) , allocSize_(0) { resize(size, doClear); } AlignedArray(const AlignedArray& rhs) : p_(0) , size_(0) , allocSize_(0) { *this = rhs; } AlignedArray& operator=(const AlignedArray& rhs) { if (allocSize_ < rhs.size_) { allocCopy(rhs.size_, rhs.p_, rhs.size_); } else { copy(p_, rhs.p_, rhs.size_); } size_ = rhs.size_; return *this; } #if (CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11) AlignedArray(AlignedArray&& rhs) CYBOZU_NOEXCEPT : p_(rhs.p_) , size_(rhs.size_) , allocSize_(rhs.allocSize_) { rhs.p_ = 0; rhs.size_ = 0; rhs.allocSize_ = 0; } AlignedArray& operator=(AlignedArray&& rhs) CYBOZU_NOEXCEPT { swap(rhs); rhs.clear(); return *this; } #endif /* don't clear buffer with zero if doClear is false @note don't free if shrinked */ void resize(size_t size, bool doClear = defaultDoClear) { // shrink if (size <= size_) { size_ = size; return; } // realloc if necessary if (size > allocSize_) { allocCopy(size, p_, size_); } if (doClear) setZero(p_ + size_, size - size_); size_ = size; } void clear() // not free { size_ = 0; } ~AlignedArray() { AlignedFree(p_); } void swap(AlignedArray& rhs) CYBOZU_NOEXCEPT { std::swap(p_, rhs.p_); std::swap(size_, rhs.size_); std::swap(allocSize_, rhs.allocSize_); } T& operator[](size_t idx) CYBOZU_NOEXCEPT { return p_[idx]; } const T& operator[](size_t idx) const CYBOZU_NOEXCEPT { return p_[idx]; } size_t size() const CYBOZU_NOEXCEPT { return size_; } bool empty() const CYBOZU_NOEXCEPT { return size_ == 0; } T* begin() CYBOZU_NOEXCEPT { return p_; } T* end() CYBOZU_NOEXCEPT { return p_ + size_; } const T* begin() const CYBOZU_NOEXCEPT { return p_; } const T* end() const CYBOZU_NOEXCEPT { return p_ + size_; } T* data() CYBOZU_NOEXCEPT { return p_; } const T* data() const CYBOZU_NOEXCEPT { return p_; } #if (CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11) const T* cbegin() const CYBOZU_NOEXCEPT { return p_; } const T* cend() const CYBOZU_NOEXCEPT { return p_ + size_; } #endif }; } // cybozu