aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/github.com/dexon-foundation/mcl/include/cybozu/array.hpp
blob: 30df3667d415da6ad50865229bd601db7f6aefca (plain) (tree)




































































































































































































                                                                                 
#pragma once

/**
    @file
    @brief scoped array and aligned array

    @author MITSUNARI Shigeo(@herumi)
*/
#include <new>
#include <utility>
#ifdef _WIN32
    #include <malloc.h>
#else
    #include <stdlib.h>
#endif
#include <cybozu/inttype.hpp>

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 T>
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 T, size_t N = 16, bool defaultDoClear = true>
class AlignedArray {
    T *p_;
    size_t size_;
    size_t allocSize_;
    T *alloc(size_t size) const
    {
        T *p = static_cast<T*>(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