add SkVptr()

I was wondering how feasible using this to make downcasts safe would be.
These tests would need to build and pass on all our bots, at least.

Change-Id: I1753ba58841bf6c17d6ac3af7374518356e1bb05
Reviewed-on: https://skia-review.googlesource.com/81180
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
This commit is contained in:
Mike Klein 2017-12-06 12:27:44 -05:00 committed by Skia Commit-Bot
parent d34c4a3727
commit 0554d497f8
3 changed files with 86 additions and 0 deletions

View File

@ -274,6 +274,7 @@ tests_sources = [
"$_tests/VkHeapTests.cpp",
"$_tests/VkUploadPixelsTests.cpp",
"$_tests/VkWrapTests.cpp",
"$_tests/VptrTest.cpp",
"$_tests/WindowRectanglesTest.cpp",
"$_tests/WritePixelsTest.cpp",
"$_tests/Writer32Test.cpp",

24
src/core/SkVptr.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkVptr_DEFINED
#define SkVptr_DEFINED
#include <string.h>
#include <type_traits>
// Experimentally, see if we can get at the vptr of objects with one.
template <typename T>
static inline void* SkVptr(const T& object) {
static_assert(std::has_virtual_destructor<T>::value, "");
void* vptr;
memcpy(&vptr, (const void*)&object, sizeof(vptr));
return vptr;
}
#endif//SkVptr_DEFINED

61
tests/VptrTest.cpp Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkMakeUnique.h"
#include "SkVptr.h"
#include "Test.h"
namespace {
struct Base {
virtual ~Base() = default;
virtual size_t val() const = 0;
};
struct SubclassA : public Base {
SubclassA(size_t val) : fVal(val) {}
size_t val() const override { return fVal; }
size_t fVal;
};
struct SubclassB : public Base {
SubclassB() {}
size_t val() const override { return 42; }
};
}
DEF_TEST(Vptr, r) {
std::unique_ptr<Base> a = skstd::make_unique<SubclassA>(21),
b = skstd::make_unique<SubclassB>(),
c = skstd::make_unique<SubclassA>(22),
d = skstd::make_unique<SubclassB>();
// These 4 objects all have unique identities.
REPORTER_ASSERT(r, a != b);
REPORTER_ASSERT(r, a != c);
REPORTER_ASSERT(r, a != d);
REPORTER_ASSERT(r, b != c);
REPORTER_ASSERT(r, b != d);
REPORTER_ASSERT(r, c != d);
// Only b and d have the same val().
REPORTER_ASSERT(r, a->val() != b->val());
REPORTER_ASSERT(r, a->val() != c->val());
REPORTER_ASSERT(r, a->val() != d->val());
REPORTER_ASSERT(r, b->val() != c->val());
REPORTER_ASSERT(r, b->val() == d->val());
REPORTER_ASSERT(r, c->val() != d->val());
// SkVptr() returns the same value for objects of the same concrete type.
REPORTER_ASSERT(r, SkVptr(*a) == SkVptr(*c));
REPORTER_ASSERT(r, SkVptr(*b) == SkVptr(*d));
REPORTER_ASSERT(r, SkVptr(*a) != SkVptr(*b));
}