Make SkFunctionWrapper a better wrapper.

SkFunctionWrapper was made to be a simple abstraction over existing
resource release functions which generally follow a specific pattern of
returning void and taking a pointer to the underlying type. However,
this has been observed to be an unnecessary limit. This makes it more
generic while also making the call sites a little less brittle.

This change also uncovered an issue in msvc v19.20 to v19.22, see
https://developercommunity.visualstudio.com/content/problem/698192/in-templateusing-decltype-is-void.html
To work around this, several otherwise redundant '&' are used.

There was an attempt to take references to functions instead of pointers
to functions which greatly simplifies the intermediate wrappers.
However, that uncovered another issue in msvc, see
https://developercommunity.visualstudio.com/content/problem/699878/function-to-pointer.html

Change-Id: I54ab945ed9d9cfd0204d4d6650c2fde47cc9e175
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/235105
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Herb Derby <herb@google.com>
This commit is contained in:
Ben Wagner 2019-08-16 11:36:58 -04:00 committed by Skia Commit-Bot
parent 6f1ff9fca1
commit 723a877d0c
9 changed files with 44 additions and 40 deletions

View File

@ -47,8 +47,12 @@ template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffs
return reinterpret_cast<D*>(reinterpret_cast<sknonstd::same_cv_t<char, D>*>(ptr) + byteOffset);
}
template <typename R, typename T, R (*P)(T*)> struct SkFunctionWrapper {
R operator()(T* t) { return P(t); }
// TODO: when C++17 the language is available, use template <auto P>
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)...);
}
};
/** \class SkAutoTCallVProc
@ -60,9 +64,10 @@ template <typename R, typename T, R (*P)(T*)> struct SkFunctionWrapper {
function.
*/
template <typename T, void (*P)(T*)> class SkAutoTCallVProc
: public std::unique_ptr<T, SkFunctionWrapper<void, T, P>> {
: public std::unique_ptr<T, SkFunctionWrapper<skstd::remove_pointer_t<decltype(P)>, P>> {
public:
SkAutoTCallVProc(T* obj): std::unique_ptr<T, SkFunctionWrapper<void, T, P>>(obj) {}
SkAutoTCallVProc(T* obj)
: std::unique_ptr<T, SkFunctionWrapper<skstd::remove_pointer_t<decltype(P)>, P>>(obj) {}
operator T*() const { return this->get(); }
};
@ -259,7 +264,7 @@ public:
T* release() { return fPtr.release(); }
private:
std::unique_ptr<T, SkFunctionWrapper<void, void, sk_free>> fPtr;
std::unique_ptr<T, SkFunctionWrapper<decltype(sk_free), sk_free>> fPtr;
};
template <size_t kCountRequested, typename T> class SkAutoSTMalloc {
@ -434,7 +439,7 @@ private:
SkAlignedSStorage<sizeof(T)*N> fStorage;
};
using SkAutoFree = std::unique_ptr<void, SkFunctionWrapper<void, void, sk_free>>;
using SkAutoFree = std::unique_ptr<void, SkFunctionWrapper<decltype(sk_free), sk_free>>;
template<typename C, std::size_t... Is>
constexpr auto SkMakeArrayFromIndexSequence(C c, skstd::index_sequence<Is...>)

View File

@ -25,10 +25,9 @@ bool TextBreaker::initialize(SkSpan<const char> text, UBreakIteratorType type) {
UErrorCode status = U_ZERO_ERROR;
fIterator = nullptr;
fSize = text.size();
UText utf8UText = UTEXT_INITIALIZER;
utext_openUTF8(&utf8UText, text.begin(), text.size(), &status);
fAutoClose =
std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>>(&utf8UText);
UText sUtf8UText = UTEXT_INITIALIZER;
std::unique_ptr<UText, SkFunctionWrapper<decltype(utext_close), utext_close>> utf8UText(
utext_openUTF8(&sUtf8UText, text.begin(), text.size(), &status));
if (U_FAILURE(status)) {
SkDebugf("Could not create utf8UText: %s", u_errorName(status));
return false;
@ -39,7 +38,7 @@ bool TextBreaker::initialize(SkSpan<const char> text, UBreakIteratorType type) {
SK_ABORT("");
}
ubrk_setUText(fIterator.get(), &utf8UText, &status);
ubrk_setUText(fIterator.get(), utf8UText.get(), &status);
if (U_FAILURE(status)) {
SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
return false;

View File

@ -75,8 +75,7 @@ public:
bool eof() { return fPos == icu::BreakIterator::DONE; }
private:
std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> fAutoClose;
std::unique_ptr<UBreakIterator, SkFunctionWrapper<void, UBreakIterator, ubrk_close>> fIterator;
std::unique_ptr<UBreakIterator, SkFunctionWrapper<decltype(ubrk_close), ubrk_close>> fIterator;
bool fInitialized;
int32_t fPos;
size_t fSize;

View File

@ -55,13 +55,15 @@ template <> struct is_bitmask_enum<hb_buffer_flags_t> : std::true_type {};
}
namespace {
template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
using HBBlob = resource<hb_blob_t , hb_blob_destroy >;
using HBFace = resource<hb_face_t , hb_face_destroy >;
using HBFont = resource<hb_font_t , hb_font_destroy >;
using HBBuffer = resource<hb_buffer_t , hb_buffer_destroy>;
using ICUBiDi = resource<UBiDi , ubidi_close >;
using ICUBrk = resource<UBreakIterator, ubrk_close >;
template <typename T, void(*P)(T*)> using resource =
std::unique_ptr<T, SkFunctionWrapper<skstd::remove_pointer_t<decltype(P)>, P>>;
using HBBlob = resource<hb_blob_t , &hb_blob_destroy >;
using HBFace = resource<hb_face_t , &hb_face_destroy >;
using HBFont = resource<hb_font_t , &hb_font_destroy >;
using HBBuffer = resource<hb_buffer_t , &hb_buffer_destroy>;
using ICUBiDi = resource<UBiDi , &ubidi_close >;
using ICUBrk = resource<UBreakIterator, &ubrk_close >;
using ICUUText = std::unique_ptr<UText, SkFunctionWrapper<decltype(utext_close), utext_close>>;
HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
size_t size = asset->getLength();
@ -863,14 +865,13 @@ void ShaperDrivenWrapper::wrap(char const * const utf8, size_t utf8Bytes,
UBreakIterator& breakIterator = *fLineBreakIterator;
{
UErrorCode status = U_ZERO_ERROR;
UText utf8UText = UTEXT_INITIALIZER;
utext_openUTF8(&utf8UText, utf8Start, utf8runLength, &status);
std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
UText sUtf8UText = UTEXT_INITIALIZER;
ICUUText utf8UText(utext_openUTF8(&sUtf8UText, utf8Start, utf8runLength, &status));
if (U_FAILURE(status)) {
SkDebugf("Could not create utf8UText: %s", u_errorName(status));
return;
}
ubrk_setUText(&breakIterator, &utf8UText, &status);
ubrk_setUText(&breakIterator, utf8UText.get(), &status);
if (U_FAILURE(status)) {
SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
return;
@ -966,20 +967,19 @@ void ShapeThenWrap::wrap(char const * const utf8, size_t utf8Bytes,
UBreakIterator& graphemeBreakIterator = *fGraphemeBreakIterator;
{
UErrorCode status = U_ZERO_ERROR;
UText utf8UText = UTEXT_INITIALIZER;
utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
UText sUtf8UText = UTEXT_INITIALIZER;
ICUUText utf8UText(utext_openUTF8(&sUtf8UText, utf8, utf8Bytes, &status));
if (U_FAILURE(status)) {
SkDebugf("Could not create utf8UText: %s", u_errorName(status));
return;
}
ubrk_setUText(&lineBreakIterator, &utf8UText, &status);
ubrk_setUText(&lineBreakIterator, utf8UText.get(), &status);
if (U_FAILURE(status)) {
SkDebugf("Could not setText on line break iterator: %s", u_errorName(status));
return;
}
ubrk_setUText(&graphemeBreakIterator, &utf8UText, &status);
ubrk_setUText(&graphemeBreakIterator, utf8UText.get(), &status);
if (U_FAILURE(status)) {
SkDebugf("Could not setText on grapheme break iterator: %s", u_errorName(status));
return;

View File

@ -237,7 +237,7 @@ template <> struct SkMask::AlphaIter<SkMask::kLCD16_Format> {
* Stack class used to manage the fImage buffer in a SkMask.
* When this object loses scope, the buffer is freed with SkMask::FreeImage().
*/
using SkAutoMaskFreeImage = std::unique_ptr<uint8_t,SkFunctionWrapper<void,void,SkMask::FreeImage>>;
using SkAutoMaskFreeImage = std::unique_ptr<uint8_t, SkFunctionWrapper<decltype(SkMask::FreeImage), SkMask::FreeImage>>;
#define SkAutoMaskFreeImage(...) SK_REQUIRE_LOCAL_VAR(SkAutoMaskFreeImage)
#endif

View File

@ -16,11 +16,12 @@
#include "hb.h"
#include "hb-subset.h"
template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
using HBBlob = resource<hb_blob_t, hb_blob_destroy>;
using HBFace = resource<hb_face_t, hb_face_destroy>;
using HBSubsetInput = resource<hb_subset_input_t, hb_subset_input_destroy>;
using HBSet = resource<hb_set_t, hb_set_destroy>;
template <class T, void(*P)(T*)> using resource =
std::unique_ptr<T, SkFunctionWrapper<skstd::remove_pointer_t<decltype(P)>, P>>;
using HBBlob = resource<hb_blob_t, &hb_blob_destroy>;
using HBFace = resource<hb_face_t, &hb_face_destroy>;
using HBSubsetInput = resource<hb_subset_input_t, &hb_subset_input_destroy>;
using HBSet = resource<hb_set_t, &hb_set_destroy>;
static HBBlob to_blob(sk_sp<SkData> data) {
using blob_size_t = SkCallableTraits<decltype(hb_blob_create)>::argument<1>::type;

View File

@ -297,7 +297,7 @@ static void unref_ft_library() {
struct SkFaceRec {
SkFaceRec* fNext;
std::unique_ptr<FT_FaceRec, SkFunctionWrapper<FT_Error, FT_FaceRec, FT_Done_Face>> fFace;
std::unique_ptr<FT_FaceRec, SkFunctionWrapper<decltype(FT_Done_Face), FT_Done_Face>> fFace;
FT_StreamRec fFTStream;
std::unique_ptr<SkStreamAsset> fSkStream;
uint32_t fRefCnt;
@ -529,7 +529,7 @@ protected:
void generateFontMetrics(SkFontMetrics*) override;
private:
using UnrefFTFace = SkFunctionWrapper<void, SkFaceRec, unref_ft_face>;
using UnrefFTFace = SkFunctionWrapper<decltype(unref_ft_face), unref_ft_face>;
std::unique_ptr<SkFaceRec, UnrefFTFace> fFaceRec;
FT_Face fFace; // Borrowed face from gFaceRecHead.
@ -932,7 +932,7 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp<SkTypeface> typeface,
fLoadGlyphFlags = loadFlags;
}
using DoneFTSize = SkFunctionWrapper<FT_Error, skstd::remove_pointer_t<FT_Size>, FT_Done_Size>;
using DoneFTSize = SkFunctionWrapper<decltype(FT_Done_Size), FT_Done_Size>;
std::unique_ptr<skstd::remove_pointer_t<FT_Size>, DoneFTSize> ftSize([this]() -> FT_Size {
FT_Size size;
FT_Error err = FT_New_Size(fFaceRec->fFace.get(), &size);

View File

@ -51,7 +51,7 @@ public:
}
private:
std::unique_ptr<uint32_t, SkFunctionWrapper<void, void, sk_free>> fBitData;
std::unique_ptr<uint32_t, SkFunctionWrapper<decltype(sk_free), sk_free>> fBitData;
size_t fDwordCount; // Dword (32-bit) count of the bitset.
uint32_t* internalGet(int index) const {

View File

@ -19,7 +19,7 @@
template <typename CFRef> using SkUniqueCFRef =
std::unique_ptr<skstd::remove_pointer_t<CFRef>,
SkFunctionWrapper<void, skstd::remove_pointer_t<CFTypeRef>, CFRelease>>;
SkFunctionWrapper<decltype(CFRelease), CFRelease>>;
#endif
#endif