blob: 23cbc15ac768260c55914f0417ced1dcc65764a9 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_WTF_TEST_HELPER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_WTF_TEST_HELPER_H_
#include <type_traits>
#include "base/memory/scoped_refptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
namespace WTF {
class DestructCounter {
USING_FAST_MALLOC(DestructCounter);
public:
explicit DestructCounter(int i, int* destruct_number)
: i_(i), destruct_number_(destruct_number) {}
~DestructCounter() { ++(*destruct_number_); }
int Get() const { return i_; }
private:
int i_;
int* destruct_number_;
};
class MoveOnly {
DISALLOW_NEW();
public:
explicit MoveOnly(int i = 0) : i_(i) {}
MoveOnly(MoveOnly&& other) : i_(other.i_) { other.i_ = 0; }
MoveOnly& operator=(MoveOnly&& other) {
if (this != &other) {
i_ = other.i_;
other.i_ = 0;
}
return *this;
}
int Value() const { return i_; }
private:
int i_;
};
class MoveOnlyHashValue {
public:
// kEmpty and kDeleted have special meanings when MoveOnlyHashValue is used as
// the key of a hash table.
enum { kEmpty = 0, kDeleted = -1, kMovedOut = -2 };
explicit MoveOnlyHashValue(int value = kEmpty, int id = 0)
: value_(value), id_(id) {}
MoveOnlyHashValue(MoveOnlyHashValue&& other)
: value_(other.value_), id_(other.id_) {
other.value_ = kMovedOut;
other.id_ = 0;
}
MoveOnlyHashValue& operator=(MoveOnlyHashValue&& other) {
value_ = other.value_;
id_ = other.id_;
other.value_ = kMovedOut;
other.id_ = 0;
return *this;
}
int Value() const { return value_; }
// id() is used for distinguishing MoveOnlys with the same value().
int Id() const { return id_; }
private:
MoveOnlyHashValue(const MoveOnlyHashValue&) = delete;
MoveOnlyHashValue& operator=(const MoveOnlyHashValue&) = delete;
int value_;
int id_;
};
struct MoveOnlyHashTraits : public GenericHashTraits<MoveOnlyHashValue> {
// This is actually true, but we pretend that it's false to disable the
// optimization.
static const bool kEmptyValueIsZero = false;
static const bool kHasIsEmptyValueFunction = true;
static bool IsEmptyValue(const MoveOnlyHashValue& value) {
return value.Value() == MoveOnlyHashValue::kEmpty;
}
static void ConstructDeletedValue(MoveOnlyHashValue& slot, bool) {
slot = MoveOnlyHashValue(MoveOnlyHashValue::kDeleted);
}
static bool IsDeletedValue(const MoveOnlyHashValue& value) {
return value.Value() == MoveOnlyHashValue::kDeleted;
}
};
struct MoveOnlyHash {
static unsigned GetHash(const MoveOnlyHashValue& value) {
return DefaultHash<int>::Hash::GetHash(value.Value());
}
static bool Equal(const MoveOnlyHashValue& left,
const MoveOnlyHashValue& right) {
return DefaultHash<int>::Hash::Equal(left.Value(), right.Value());
}
static const bool safe_to_compare_to_empty_or_deleted = true;
};
template <>
struct HashTraits<MoveOnlyHashValue> : public MoveOnlyHashTraits {};
template <>
struct DefaultHash<MoveOnlyHashValue> {
using Hash = MoveOnlyHash;
};
class CountCopy final {
public:
static int* const kDeletedValue;
CountCopy() : counter_(nullptr) {}
explicit CountCopy(int* counter) : counter_(counter) {}
explicit CountCopy(int& counter) : counter_(&counter) {}
CountCopy(const CountCopy& other) : counter_(other.counter_) {
if (counter_ && counter_ != kDeletedValue)
++*counter_;
}
CountCopy& operator=(const CountCopy& other) {
counter_ = other.counter_;
if (counter_ && counter_ != kDeletedValue)
++*counter_;
return *this;
}
const int* Counter() const { return counter_; }
private:
int* counter_;
};
struct CountCopyHashTraits : public GenericHashTraits<CountCopy> {
static const bool kEmptyValueIsZero = false;
static const bool kHasIsEmptyValueFunction = true;
static bool IsEmptyValue(const CountCopy& value) { return !value.Counter(); }
static void ConstructDeletedValue(CountCopy& slot, bool) {
slot = CountCopy(CountCopy::kDeletedValue);
}
static bool IsDeletedValue(const CountCopy& value) {
return value.Counter() == CountCopy::kDeletedValue;
}
};
struct CountCopyHash : public PtrHash<const int*> {
static unsigned GetHash(const CountCopy& value) {
return PtrHash<const int>::GetHash(value.Counter());
}
static bool Equal(const CountCopy& left, const CountCopy& right) {
return PtrHash<const int>::Equal(left.Counter(), right.Counter());
}
static const bool safe_to_compare_to_empty_or_deleted = true;
};
template <>
struct HashTraits<CountCopy> : public CountCopyHashTraits {};
template <>
struct DefaultHash<CountCopy> {
using Hash = CountCopyHash;
};
template <typename T>
class ValueInstanceCount final {
public:
static int* const kDeletedValue;
ValueInstanceCount() : counter_(nullptr), value_(T()) {}
explicit ValueInstanceCount(int* counter, T value = T())
: counter_(counter), value_(value) {
if (counter_ && counter_ != kDeletedValue)
++*counter_;
}
ValueInstanceCount(const ValueInstanceCount& other)
: counter_(other.counter_), value_(other.value_) {
if (counter_ && counter_ != kDeletedValue)
++*counter_;
}
ValueInstanceCount& operator=(const ValueInstanceCount& other) {
if (counter_ && counter_ != kDeletedValue)
--*counter_;
counter_ = other.counter_;
value_ = other.value_;
if (counter_ && counter_ != kDeletedValue)
++*counter_;
return *this;
}
~ValueInstanceCount() {
if (counter_ && counter_ != kDeletedValue)
--*counter_;
}
const int* Counter() const { return counter_; }
const T& Value() const { return value_; }
private:
int* counter_;
T value_;
};
template <typename T>
struct ValueInstanceCountHashTraits
: public GenericHashTraits<ValueInstanceCount<T>> {
static const bool kEmptyValueIsZero = false;
static const bool kHasIsEmptyValueFunction = true;
static bool IsEmptyValue(const ValueInstanceCount<T>& value) {
return !value.Counter();
}
static void ConstructDeletedValue(ValueInstanceCount<T>& slot, bool) {
slot = ValueInstanceCount<T>(ValueInstanceCount<T>::kDeletedValue);
}
static bool IsDeletedValue(const ValueInstanceCount<T>& value) {
return value.Counter() == ValueInstanceCount<T>::kDeletedValue;
}
};
template <typename T>
struct ValueInstanceCountHash : public PtrHash<const int*> {
static unsigned GetHash(const ValueInstanceCount<T>& value) {
return PtrHash<const int>::GetHash(value.Counter());
}
static bool Equal(const ValueInstanceCount<T>& left,
const ValueInstanceCount<T>& right) {
return PtrHash<const int>::Equal(left.Counter(), right.Counter());
}
static const bool safe_to_compare_to_empty_or_deleted = true;
};
template <typename T>
struct HashTraits<ValueInstanceCount<T>>
: public ValueInstanceCountHashTraits<T> {};
template <typename T>
struct DefaultHash<ValueInstanceCount<T>> {
using Hash = ValueInstanceCountHash<T>;
};
class DummyRefCounted : public RefCounted<DummyRefCounted> {
public:
DummyRefCounted(bool& is_deleted) : is_deleted_(is_deleted) {
is_deleted_ = false;
}
~DummyRefCounted() {
DCHECK(!is_deleted_);
is_deleted_ = true;
}
void AddRef() {
DCHECK(!is_deleted_);
WTF::RefCounted<DummyRefCounted>::AddRef();
++ref_invokes_count_;
}
void Release() {
DCHECK(!is_deleted_);
WTF::RefCounted<DummyRefCounted>::Release();
}
static int ref_invokes_count_;
private:
bool& is_deleted_;
};
struct Dummy {
Dummy(bool& deleted) : deleted(deleted) {}
~Dummy() { deleted = true; }
bool& deleted;
};
// WrappedInt class will fail if it was memmoved or memcpyed.
extern HashSet<void*> g_constructed_wrapped_ints;
class WrappedInt {
public:
WrappedInt(int i = 0) : original_this_ptr_(this), i_(i) {
g_constructed_wrapped_ints.insert(this);
}
WrappedInt(const WrappedInt& other) : original_this_ptr_(this), i_(other.i_) {
g_constructed_wrapped_ints.insert(this);
}
WrappedInt& operator=(const WrappedInt& other) {
i_ = other.i_;
return *this;
}
~WrappedInt() {
EXPECT_EQ(original_this_ptr_, this);
EXPECT_TRUE(g_constructed_wrapped_ints.Contains(this));
g_constructed_wrapped_ints.erase(this);
}
int Get() const { return i_; }
private:
void* original_this_ptr_;
int i_;
};
class LivenessCounter {
public:
void AddRef() { live_++; }
void Release() { live_--; }
static unsigned live_;
};
} // namespace WTF
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_WTF_TEST_HELPER_H_