#pragma once
#include "include/core/SkTypes.h"
#include "include/private/SkMalloc.h"
#include <string.h>
#include <array>
#include <cstddef>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
namespace pk {
template <typename T, T* P> struct SkFunctionWrapper {
template <typename... Args>
auto operator()(Args&&... args) const -> decltype(P(std::forward<Args>(args)...)) {
return P(std::forward<Args>(args)...);
}
};
template <typename T, void (*P)(T*)> class SkAutoTCallVProc
: public std::unique_ptr<T, SkFunctionWrapper<std::remove_pointer_t<decltype(P)>, P>> {
using inherited = std::unique_ptr<T, SkFunctionWrapper<std::remove_pointer_t<decltype(P)>, P>>;
public:
using inherited::inherited;
SkAutoTCallVProc(const SkAutoTCallVProc&) = delete;
SkAutoTCallVProc(SkAutoTCallVProc&& that) : inherited(std::move(that)) {}
operator T*() const { return this->get(); }
};
template <typename T> class SkAutoTArray {
public:
SkAutoTArray() {}
explicit SkAutoTArray(int count) {
if (count) {
fArray.reset(new T[count]);
}
}
SkAutoTArray(SkAutoTArray&& other) : fArray(std::move(other.fArray)) {
}
SkAutoTArray& operator=(SkAutoTArray&& other) {
if (this != &other) {
fArray = std::move(other.fArray);
}
return *this;
}
void reset(int count = 0) { *this = SkAutoTArray(count); }
T* get() const { return fArray.get(); }
T& operator[](int index) const {
return fArray[index];
}
const T* data() const { return fArray.get(); }
T* data() { return fArray.get(); }
private:
std::unique_ptr<T[]> fArray;
};
template <int kCountRequested, typename T> class SkAutoSTArray {
public:
SkAutoSTArray(SkAutoSTArray&&) = delete;
SkAutoSTArray(const SkAutoSTArray&) = delete;
SkAutoSTArray& operator=(SkAutoSTArray&&) = delete;
SkAutoSTArray& operator=(const SkAutoSTArray&) = delete;
SkAutoSTArray() {
fArray = nullptr;
fCount = 0;
}
SkAutoSTArray(int count) {
fArray = nullptr;
fCount = 0;
this->reset(count);
}
~SkAutoSTArray() {
this->reset(0);
}
void reset(int count) {
T* start = fArray;
T* iter = start + fCount;
while (iter > start) {
(--iter)->~T();
}
if (fCount != count) {
if (fCount > kCount) {
sk_free(fArray);
}
if (count > kCount) {
fArray = (T*) sk_malloc_throw(count, sizeof(T));
} else if (count > 0) {
fArray = (T*) fStorage;
} else {
fArray = nullptr;
}
fCount = count;
}
iter = fArray;
T* stop = fArray + count;
while (iter < stop) {
new (iter++) T;
}
}
int count() const { return fCount; }
T* get() const { return fArray; }
T* begin() { return fArray; }
const T* begin() const { return fArray; }
T* end() { return fArray + fCount; }
const T* end() const { return fArray + fCount; }
T& operator[](int index) const {
return fArray[index];
}
const T* data() const { return fArray; }
T* data() { return fArray; }
size_t size() const { return fCount; }
private:
#if defined(PK_BUILD_FOR_GOOGLE3)
static const int kMaxBytes = 4 * 1024;
static const int kCount = kCountRequested * sizeof(T) > kMaxBytes
? kMaxBytes / sizeof(T)
: kCountRequested;
#else
static const int kCount = kCountRequested;
#endif
int fCount;
T* fArray;
char fStorage[kCount * sizeof(T)];
};
template <typename T,
typename = std::enable_if_t<std::is_trivially_default_constructible<T>::value &&
std::is_trivially_destructible<T>::value>>
class SkAutoTMalloc {
public:
explicit SkAutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {}
explicit SkAutoTMalloc(size_t count)
: fPtr(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr) {}
SkAutoTMalloc(SkAutoTMalloc&&) = default;
SkAutoTMalloc& operator=(SkAutoTMalloc&&) = default;
void realloc(size_t count) {
fPtr.reset(count ? (T*)sk_realloc_throw(fPtr.release(), count * sizeof(T)) : nullptr);
}
T* reset(size_t count = 0) {
fPtr.reset(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr);
return this->get();
}
T* get() const { return fPtr.get(); }
operator T*() { return fPtr.get(); }
operator const T*() const { return fPtr.get(); }
T& operator[](int index) { return fPtr.get()[index]; }
const T& operator[](int index) const { return fPtr.get()[index]; }
const T* data() const { return fPtr.get(); }
T* data() { return fPtr.get(); }
T* release() { return fPtr.release(); }
private:
std::unique_ptr<T, SkFunctionWrapper<void(void*), sk_free>> fPtr;
};
template <size_t kCountRequested,
typename T,
typename = std::enable_if_t<std::is_trivially_default_constructible<T>::value &&
std::is_trivially_destructible<T>::value>>
class SkAutoSTMalloc {
public:
SkAutoSTMalloc() : fPtr(fTStorage) {}
SkAutoSTMalloc(size_t count) {
if (count > kCount) {
fPtr = (T*)sk_malloc_throw(count, sizeof(T));
} else if (count) {
fPtr = fTStorage;
} else {
fPtr = nullptr;
}
}
SkAutoSTMalloc(SkAutoSTMalloc&&) = delete;
SkAutoSTMalloc(const SkAutoSTMalloc&) = delete;
SkAutoSTMalloc& operator=(SkAutoSTMalloc&&) = delete;
SkAutoSTMalloc& operator=(const SkAutoSTMalloc&) = delete;
~SkAutoSTMalloc() {
if (fPtr != fTStorage) {
sk_free(fPtr);
}
}
T* reset(size_t count) {
if (fPtr != fTStorage) {
sk_free(fPtr);
}
if (count > kCount) {
fPtr = (T*)sk_malloc_throw(count, sizeof(T));
} else if (count) {
fPtr = fTStorage;
} else {
fPtr = nullptr;
}
return fPtr;
}
T* get() const { return fPtr; }
operator T*() {
return fPtr;
}
operator const T*() const {
return fPtr;
}
T& operator[](int index) {
return fPtr[index];
}
const T& operator[](int index) const {
return fPtr[index];
}
const T* data() const { return fPtr; }
T* data() { return fPtr; }
void realloc(size_t count) {
if (count > kCount) {
if (fPtr == fTStorage) {
fPtr = (T*)sk_malloc_throw(count, sizeof(T));
memcpy((void*)fPtr, fTStorage, kCount * sizeof(T));
} else {
fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
}
} else if (count) {
if (fPtr != fTStorage) {
fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
}
} else {
this->reset(0);
}
}
private:
static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
#if defined(PK_BUILD_FOR_GOOGLE3)
static const size_t kMaxBytes = 4 * 1024;
static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
? kMaxBytes / sizeof(T)
: kCountWithPadding;
#else
static const size_t kCount = kCountWithPadding;
#endif
T* fPtr;
union {
uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
T fTStorage[1]; };
};
template <typename T> void SkInPlaceDeleteCheck(T* obj, void* storage) {
if (storage == obj) {
obj->~T();
} else {
delete obj;
}
}
template<typename T, typename... Args>
T* SkInPlaceNewCheck(void* storage, size_t size, Args&&... args) {
return (sizeof(T) <= size) ? new (storage) T(std::forward<Args>(args)...)
: new T(std::forward<Args>(args)...);
}
template <int N, typename T> class SkAlignedSTStorage {
public:
SkAlignedSTStorage() {}
SkAlignedSTStorage(SkAlignedSTStorage&&) = delete;
SkAlignedSTStorage(const SkAlignedSTStorage&) = delete;
SkAlignedSTStorage& operator=(SkAlignedSTStorage&&) = delete;
SkAlignedSTStorage& operator=(const SkAlignedSTStorage&) = delete;
void* get() { return fStorage; }
const void* get() const { return fStorage; }
private:
alignas(T) char fStorage[sizeof(T)*N];
};
template<typename C, std::size_t... Is>
constexpr auto SkMakeArrayFromIndexSequence(C c, std::index_sequence<Is...> is)
-> std::array<decltype(c(std::declval<typename decltype(is)::value_type>())), sizeof...(Is)> {
return {{ c(Is)... }};
}
template<size_t N, typename C> constexpr auto SkMakeArray(C c)
-> std::array<decltype(c(std::declval<typename std::index_sequence<N>::value_type>())), N> {
return SkMakeArrayFromIndexSequence(c, std::make_index_sequence<N>{});
}
}