1 // Copyright 2019 The Chromium 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 PLATFORM_API_SERIAL_DELETE_PTR_H_
6 #define PLATFORM_API_SERIAL_DELETE_PTR_H_
7
8 #include <cassert>
9 #include <memory>
10 #include <utility>
11
12 #include "platform/api/task_runner.h"
13
14 namespace openscreen {
15
16 // A functor that deletes an object via a task on a specific TaskRunner. This is
17 // used for ensuring an object is deleted after any tasks that reference it have
18 // completed.
19 template <typename Type, typename DeleterType>
20 class SerialDelete {
21 public:
SerialDelete()22 SerialDelete() : deleter_() {}
23
SerialDelete(TaskRunner * task_runner)24 explicit SerialDelete(TaskRunner* task_runner)
25 : task_runner_(task_runner), deleter_() {
26 assert(task_runner);
27 }
28
29 template <typename DT>
SerialDelete(TaskRunner * task_runner,DT && deleter)30 SerialDelete(TaskRunner* task_runner, DT&& deleter)
31 : task_runner_(task_runner), deleter_(std::forward<DT>(deleter)) {
32 assert(task_runner);
33 }
34
operator()35 void operator()(Type* pointer) const {
36 if (task_runner_) {
37 // Deletion of the object depends on the task being run by the task
38 // runner.
39 task_runner_->PostTask(
40 [pointer, deleter = std::move(deleter_)] { deleter(pointer); });
41 }
42 }
43
44 private:
45 TaskRunner* task_runner_;
46 DeleterType deleter_;
47 };
48
49 // A wrapper around std::unique_ptr<> that uses SerialDelete<> to schedule the
50 // object's deletion.
51 template <typename Type, typename DeleterType = std::default_delete<Type>>
52 class SerialDeletePtr
53 : public std::unique_ptr<Type, SerialDelete<Type, DeleterType>> {
54 public:
SerialDeletePtr()55 SerialDeletePtr() noexcept
56 : std::unique_ptr<Type, SerialDelete<Type, DeleterType>>(
57 nullptr,
58 SerialDelete<Type, DeleterType>()) {}
59
SerialDeletePtr(TaskRunner * task_runner)60 explicit SerialDeletePtr(TaskRunner* task_runner) noexcept
61 : std::unique_ptr<Type, SerialDelete<Type, DeleterType>>(
62 nullptr,
63 SerialDelete<Type, DeleterType>(task_runner)) {
64 assert(task_runner);
65 }
66
SerialDeletePtr(TaskRunner * task_runner,std::nullptr_t)67 SerialDeletePtr(TaskRunner* task_runner, std::nullptr_t) noexcept
68 : std::unique_ptr<Type, SerialDelete<Type, DeleterType>>(
69 nullptr,
70 SerialDelete<Type, DeleterType>(task_runner)) {
71 assert(task_runner);
72 }
73
SerialDeletePtr(TaskRunner * task_runner,Type * pointer)74 SerialDeletePtr(TaskRunner* task_runner, Type* pointer) noexcept
75 : std::unique_ptr<Type, SerialDelete<Type, DeleterType>>(
76 pointer,
77 SerialDelete<Type, DeleterType>(task_runner)) {
78 assert(task_runner);
79 }
80
SerialDeletePtr(TaskRunner * task_runner,Type * pointer,typename std::conditional<std::is_reference<DeleterType>::value,DeleterType,const DeleterType &>::type deleter)81 SerialDeletePtr(
82 TaskRunner* task_runner,
83 Type* pointer,
84 typename std::conditional<std::is_reference<DeleterType>::value,
85 DeleterType,
86 const DeleterType&>::type deleter) noexcept
87 : std::unique_ptr<Type, SerialDelete<Type, DeleterType>>(
88 pointer,
89 SerialDelete<Type, DeleterType>(task_runner, deleter)) {
90 assert(task_runner);
91 }
92
SerialDeletePtr(TaskRunner * task_runner,Type * pointer,typename std::remove_reference<DeleterType>::type && deleter)93 SerialDeletePtr(
94 TaskRunner* task_runner,
95 Type* pointer,
96 typename std::remove_reference<DeleterType>::type&& deleter) noexcept
97 : std::unique_ptr<Type, SerialDelete<Type, DeleterType>>(
98 pointer,
99 SerialDelete<Type, DeleterType>(task_runner, std::move(deleter))) {
100 assert(task_runner);
101 }
102 };
103
104 template <typename Type, typename... Args>
MakeSerialDelete(TaskRunner * task_runner,Args &&...args)105 SerialDeletePtr<Type> MakeSerialDelete(TaskRunner* task_runner,
106 Args&&... args) {
107 return SerialDeletePtr<Type>(task_runner,
108 new Type(std::forward<Args>(args)...));
109 }
110
111 } // namespace openscreen
112
113 #endif // PLATFORM_API_SERIAL_DELETE_PTR_H_
114