Added skstd::optional
This is needed by the upcoming DSLParser. Change-Id: I54a0714e55feeb78894df766b14c795970f2c2d4 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/411308 Commit-Queue: Ethan Nicholas <ethannicholas@google.com> Reviewed-by: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
6576de67a4
commit
4ed2baa981
@ -478,6 +478,7 @@ skia_core_sources = [
|
||||
"$_include/private/SkTFitsIn.h",
|
||||
"$_include/private/SkTHash.h",
|
||||
"$_include/private/SkTLogic.h",
|
||||
"$_include/private/SkTOptional.h",
|
||||
"$_include/private/SkTemplates.h",
|
||||
"$_include/private/SkThreadAnnotations.h",
|
||||
"$_include/private/SkThreadID.h",
|
||||
|
@ -274,6 +274,7 @@ tests_sources = [
|
||||
"$_tests/SkShaperJSONWriterTest.cpp",
|
||||
"$_tests/SkSharedMutexTest.cpp",
|
||||
"$_tests/SkStrikeCacheTest.cpp",
|
||||
"$_tests/SkTOptionalTest.cpp",
|
||||
"$_tests/SkUTFTest.cpp",
|
||||
"$_tests/SkVMTest.cpp",
|
||||
"$_tests/SkVxTest.cpp",
|
||||
|
100
include/private/SkTOptional.h
Normal file
100
include/private/SkTOptional.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkTOptional_DEFINED
|
||||
#define SkTOptional_DEFINED
|
||||
|
||||
#include "include/core/SkTypes.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace skstd {
|
||||
|
||||
/**
|
||||
* Simple drop-in replacement for std::optional until we move to C++17. This does not have all of
|
||||
* std::optional's capabilities, but it covers our needs for the time being.
|
||||
*/
|
||||
template<typename T>
|
||||
class optional {
|
||||
public:
|
||||
optional(const optional&) = delete;
|
||||
|
||||
optional(T&& value)
|
||||
: fHasValue(true) {
|
||||
new(&fPayload.fValue) T(std::move(value));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
optional(Args&&... args)
|
||||
: optional(T(std::forward<Args...>(args...))) {}
|
||||
|
||||
optional() {}
|
||||
|
||||
optional(optional&& other) {
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
~optional() {
|
||||
if (fHasValue) {
|
||||
fPayload.fValue.~T();
|
||||
}
|
||||
}
|
||||
|
||||
optional& operator=(const optional&) = delete;
|
||||
|
||||
optional& operator=(optional&& other) {
|
||||
if (this != &other) {
|
||||
if (fHasValue) {
|
||||
fPayload.fValue.~T();
|
||||
}
|
||||
fHasValue = other.fHasValue;
|
||||
if (fHasValue) {
|
||||
new(&fPayload.fValue) T(std::move(other.fPayload.fValue));
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
SkASSERT(fHasValue);
|
||||
return fPayload.fValue;
|
||||
}
|
||||
|
||||
T* operator->() {
|
||||
SkASSERT(fHasValue);
|
||||
return &fPayload.fValue;
|
||||
}
|
||||
|
||||
const T& operator*() const {
|
||||
SkASSERT(fHasValue);
|
||||
return fPayload.fValue;
|
||||
}
|
||||
|
||||
const T* operator->() const {
|
||||
SkASSERT(fHasValue);
|
||||
return &fPayload.fValue;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return fHasValue;
|
||||
}
|
||||
|
||||
private:
|
||||
union Payload {
|
||||
T fValue;
|
||||
|
||||
Payload() {}
|
||||
|
||||
~Payload() {}
|
||||
} fPayload;
|
||||
|
||||
bool fHasValue = false;
|
||||
};
|
||||
|
||||
} // namespace skstd
|
||||
|
||||
#endif
|
70
tests/SkTOptionalTest.cpp
Normal file
70
tests/SkTOptionalTest.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/private/SkTArray.h"
|
||||
#include "include/private/SkTOptional.h"
|
||||
|
||||
#include "tests/Test.h"
|
||||
|
||||
DEF_TEST(SkTOptionalEmpty, r) {
|
||||
skstd::optional<int> o;
|
||||
REPORTER_ASSERT(r, !o);
|
||||
}
|
||||
|
||||
DEF_TEST(SkTOptionalValue, r) {
|
||||
skstd::optional<const char*> o("test");
|
||||
REPORTER_ASSERT(r, o);
|
||||
REPORTER_ASSERT(r, !strcmp(*o, "test"));
|
||||
}
|
||||
|
||||
DEF_TEST(SkTOptionalAssignment, r) {
|
||||
skstd::optional<SkTArray<int>> o;
|
||||
REPORTER_ASSERT(r, !o);
|
||||
|
||||
o = skstd::optional<SkTArray<int>>(50);
|
||||
REPORTER_ASSERT(r, o);
|
||||
REPORTER_ASSERT(r, o->capacity() == 50);
|
||||
|
||||
o = skstd::optional<SkTArray<int>>(SkTArray<int>(100));
|
||||
REPORTER_ASSERT(r, o);
|
||||
REPORTER_ASSERT(r, o->capacity() == 100);
|
||||
|
||||
o = skstd::optional<SkTArray<int>>();
|
||||
REPORTER_ASSERT(r, !o);
|
||||
}
|
||||
|
||||
DEF_TEST(SkTOptionalNoDefaultConstructor, r) {
|
||||
class NoDefaultConstructor {
|
||||
public:
|
||||
NoDefaultConstructor(int value)
|
||||
: fValue(value) {}
|
||||
|
||||
int fValue;
|
||||
};
|
||||
|
||||
skstd::optional<NoDefaultConstructor> o1;
|
||||
REPORTER_ASSERT(r, !o1);
|
||||
skstd::optional<NoDefaultConstructor> o2(5);
|
||||
REPORTER_ASSERT(r, o2);
|
||||
REPORTER_ASSERT(r, o2->fValue == 5);
|
||||
o1 = std::move(o2);
|
||||
REPORTER_ASSERT(r, o1);
|
||||
REPORTER_ASSERT(r, o1->fValue == 5);
|
||||
}
|
||||
|
||||
DEF_TEST(SkTOptionalSelfAssignment, r) {
|
||||
skstd::optional<SkString> empty;
|
||||
skstd::optional<SkString>& emptyRef = empty;
|
||||
empty = std::move(emptyRef);
|
||||
REPORTER_ASSERT(r, !empty);
|
||||
|
||||
skstd::optional<SkString> full("full");
|
||||
skstd::optional<SkString>& fullRef = full;
|
||||
full = std::move(fullRef);
|
||||
REPORTER_ASSERT(r, full);
|
||||
REPORTER_ASSERT(r, *full == SkString("full"));
|
||||
}
|
Loading…
Reference in New Issue
Block a user