/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file.
*/
This file contains light-weight template classes for type-safe and exception-safe resource management.
*/
/** * Marks a local variable as known to be unused (to avoid warnings). * Note that this does *not* prevent the local variable from being optimized away.
*/ template<typename T> inlinevoid sk_ignore_unused_variable(const T&) { }
/** * This is a general purpose absolute-value function. * See SkAbs32 in (SkSafe32.h) for a 32-bit int specific version that asserts.
*/ template <typename T> staticinline T SkTAbs(T value) { if (value < 0) {
value = -value;
} return value;
}
/** * Returns a pointer to a D which comes immediately after S[count].
*/ template <typename D, typename S> inline D* SkTAfter(S* ptr, size_t count = 1) { returnreinterpret_cast<D*>(ptr + count);
}
/** * Returns a pointer to a D which comes byteOffset bytes after S.
*/ template <typename D, typename S> inline D* SkTAddOffset(S* ptr, ptrdiff_t byteOffset) { // The intermediate char* has the same cv-ness as D as this produces better error messages. // This relies on the fact that reinterpret_cast can add constness, but cannot remove it. returnreinterpret_cast<D*>(reinterpret_cast<sknonstd::same_cv_t<char, D>*>(ptr) + byteOffset);
}
template <auto F> using SkFunctionObject =
SkOverloadedFunctionObject<std::remove_pointer_t<decltype(F)>, F>;
/** \class SkAutoTCallVProc
Call a function when this goes out of scope. The template uses two parameters, the object, and a function that is to be called in the destructor. If release() is called, the object reference is set to null. If the object reference is null when the destructor is called, we do not call the function.
*/ template <typename T, void (*P)(T*)> class SkAutoTCallVProc
: public std::unique_ptr<T, SkFunctionObject<P>> { using inherited = std::unique_ptr<T, SkFunctionObject<P>>; public: using inherited::inherited;
SkAutoTCallVProc(const SkAutoTCallVProc&) = delete;
SkAutoTCallVProc(SkAutoTCallVProc&& that) : inherited(std::move(that)) {}
operator T*() const { return this->get(); }
};
namespace skia_private { /** Allocate an array of T elements, and free the array in the destructor
*/ template <typename T> class AutoTArray { public:
AutoTArray() {} // Allocate size number of T elements explicit AutoTArray(size_t size) {
fSize = check_size_bytes_too_big<T>(size);
fData.reset(size > 0 ? new T[size] : nullptr);
}
// TODO: remove when all uses are gone. explicit AutoTArray(int size) : AutoTArray(SkToSizeT(size)) {}
// It's safe to use fItemArray + fSize because if fItemArray is nullptr then adding 0 is // valid and returns nullptr. See [expr.add] in the C++ standard.
T* end() { if (fData == nullptr) {
SkASSERT(fSize == 0);
} return fData + fSize;
} const T* end() const { if (fData == nullptr) {
SkASSERT(fSize == 0);
} return fData + fSize;
}
/** Wraps AutoTArray, with room for kCountRequested elements preallocated.
*/ template <int kCountRequested, typename T> class AutoSTArray { public:
AutoSTArray(AutoSTArray&&) = delete;
AutoSTArray(const AutoSTArray&) = delete;
AutoSTArray& operator=(AutoSTArray&&) = delete;
AutoSTArray& operator=(const AutoSTArray&) = delete;
/** Initialize with no objects */
AutoSTArray() {
fArray = nullptr;
fCount = 0;
}
/** Allocate count number of T elements
*/
AutoSTArray(int count) {
fArray = nullptr;
fCount = 0;
this->reset(count);
}
~AutoSTArray() {
this->reset(0);
}
/** Destroys previous objects in the array and default constructs count number of objects */ void reset(int count) {
T* start = fArray;
T* iter = start + fCount; while (iter > start) {
(--iter)->~T();
}
SkASSERT(count >= 0); if (fCount != count) { if (fCount > kCount) { // 'fArray' was allocated last time so free it now
SkASSERT((T*) fStorage != fArray);
sk_free(fArray);
}
private: #ifdefined(SK_BUILD_FOR_GOOGLE3) // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, // but some functions have multiple large stack allocations. staticconstint kMaxBytes = 4 * 1024; staticconstint kCount = kCountRequested * sizeof(T) > kMaxBytes
? kMaxBytes / sizeof(T)
: kCountRequested; #else staticconstint kCount = kCountRequested; #endif
int fCount;
T* fArray;
alignas(T) char fStorage[kCount * sizeof(T)];
};
/** Manages an array of T elements, freeing the array in the destructor. * Does NOT call any constructors/destructors on T (T must be POD).
*/ template <typename T, typename = std::enable_if_t<std::is_trivially_default_constructible<T>::value &&
std::is_trivially_destructible<T>::value>> class AutoTMalloc { public: /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */ explicit AutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {}
/** Allocates space for 'count' Ts. */ explicit AutoTMalloc(size_t count)
: fPtr(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr) {}
/** Resize the memory area pointed to by the current ptr preserving contents. */ void realloc(size_t count) {
fPtr.reset(count ? (T*)sk_realloc_throw(fPtr.release(), count * sizeof(T)) : nullptr);
}
/** Resize the memory area pointed to by the current ptr without preserving contents. */
T* reset(size_t count = 0) {
fPtr.reset(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr); return this->get();
}
/** * Transfer ownership of the ptr to the caller, setting the internal * pointer to NULL. Note that this differs from get(), which also returns * the pointer, but it does not transfer ownership.
*/
T* release() { return fPtr.release(); }
// Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent 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));
}
} elseif (count) { if (fPtr != fTStorage) {
fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
}
} else {
this->reset(0);
}
}
private: // Since we use uint32_t storage, we might be able to get more elements for free. staticconst size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T); #ifdefined(SK_BUILD_FOR_GOOGLE3) // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions // have multiple large stack allocations. staticconst size_t kMaxBytes = 4 * 1024; staticconst size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
? kMaxBytes / sizeof(T)
: kCountWithPadding; #else staticconst size_t kCount = kCountWithPadding; #endif
T* fPtr; union {
uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
T fTStorage[1]; // do NOT want to invoke T::T()
};
};
using UniqueVoidPtr = std::unique_ptr<void, SkOverloadedFunctionObject<void(void*), sk_free>>;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.