1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
6#define INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
7
8#include <type_traits>
9
10#include "cppgc/type-traits.h"
11
12namespace cppgc {
13namespace internal {
14
15using FinalizationCallback = void (*)(void*);
16
17template <typename T, typename = void>
18struct HasFinalizeGarbageCollectedObject : std::false_type {};
19
20template <typename T>
21struct HasFinalizeGarbageCollectedObject<
22    T,
23    std::void_t<decltype(std::declval<T>().FinalizeGarbageCollectedObject())>>
24    : std::true_type {};
25
26// The FinalizerTraitImpl specifies how to finalize objects.
27template <typename T, bool isFinalized>
28struct FinalizerTraitImpl;
29
30template <typename T>
31struct FinalizerTraitImpl<T, true> {
32 private:
33  // Dispatch to custom FinalizeGarbageCollectedObject().
34  struct Custom {
35    static void Call(void* obj) {
36      static_cast<T*>(obj)->FinalizeGarbageCollectedObject();
37    }
38  };
39
40  // Dispatch to regular destructor.
41  struct Destructor {
42    static void Call(void* obj) { static_cast<T*>(obj)->~T(); }
43  };
44
45  using FinalizeImpl =
46      std::conditional_t<HasFinalizeGarbageCollectedObject<T>::value, Custom,
47                         Destructor>;
48
49 public:
50  static void Finalize(void* obj) {
51    static_assert(sizeof(T), "T must be fully defined");
52    FinalizeImpl::Call(obj);
53  }
54};
55
56template <typename T>
57struct FinalizerTraitImpl<T, false> {
58  static void Finalize(void* obj) {
59    static_assert(sizeof(T), "T must be fully defined");
60  }
61};
62
63// The FinalizerTrait is used to determine if a type requires finalization and
64// what finalization means.
65template <typename T>
66struct FinalizerTrait {
67 private:
68  // Object has a finalizer if it has
69  // - a custom FinalizeGarbageCollectedObject method, or
70  // - a destructor.
71  static constexpr bool kNonTrivialFinalizer =
72      internal::HasFinalizeGarbageCollectedObject<T>::value ||
73      !std::is_trivially_destructible<typename std::remove_cv<T>::type>::value;
74
75  static void Finalize(void* obj) {
76    internal::FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
77  }
78
79 public:
80  static constexpr bool HasFinalizer() { return kNonTrivialFinalizer; }
81
82  // The callback used to finalize an object of type T.
83  static constexpr FinalizationCallback kCallback =
84      kNonTrivialFinalizer ? Finalize : nullptr;
85};
86
87template <typename T>
88constexpr FinalizationCallback FinalizerTrait<T>::kCallback;
89
90}  // namespace internal
91}  // namespace cppgc
92
93#endif  // INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
94