Welcome to mirror list, hosted at ThFree Co, Russian Federation.

BLI_resource_collector.hh « blenlib « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 70804ceb1f159da178e1568632625f9b7bc7e45e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#pragma once

/** \file
 * \ingroup bli
 *
 * A ResourceCollector holds an arbitrary set of resources, that will be destructed and/or freed
 * when the ResourceCollector is destructed. This is useful when some object has to take ownership
 * of other objects, but it does not know the type of those other objects.
 *
 * Resources owned by the ResourceCollector will be freed in reverse order. That allows resources
 * that are added later to depend on resources that have been added before.
 */

#include "BLI_linear_allocator.hh"
#include "BLI_utility_mixins.hh"
#include "BLI_vector.hh"

namespace blender {

class ResourceCollector : NonCopyable, NonMovable {
 private:
  struct ResourceData {
    void *data;
    void (*free)(void *data);
    const char *debug_name;
  };

  LinearAllocator<> m_allocator;
  Vector<ResourceData> m_resources;

 public:
  ResourceCollector() = default;

  ~ResourceCollector()
  {
    /* Free in reversed order. */
    for (int64_t i = m_resources.size(); i--;) {
      ResourceData &data = m_resources[i];
      data.free(data.data);
    }
  }

  /**
   * Pass ownership of the resource to the ResourceCollector. It will be destructed and freed when
   * the collector is destructed.
   */
  template<typename T> void add(std::unique_ptr<T> resource, const char *name)
  {
    BLI_assert(resource.get() != nullptr);
    this->add(
        resource.release(),
        [](void *data) {
          T *typed_data = reinterpret_cast<T *>(data);
          delete typed_data;
        },
        name);
  }

  /**
   * Pass ownership of the resource to the ResourceCollector. It will be destructed when the
   * collector is destructed.
   */
  template<typename T> void add(destruct_ptr<T> resource, const char *name)
  {
    /* There is no need to keep track of such types. */
    if (std::is_trivially_destructible_v<T>) {
      resource.release();
      return;
    }

    BLI_assert(resource.get() != nullptr);
    this->add(
        resource.release(),
        [](void *data) {
          T *typed_data = reinterpret_cast<T *>(data);
          typed_data->~T();
        },
        name);
  }

  /**
   * Pass ownership of some resource to the ResourceCollector. The given free function will be
   * called when the collector is destructed.
   */
  void add(void *userdata, void (*free)(void *), const char *name)
  {
    ResourceData data;
    data.debug_name = name;
    data.data = userdata;
    data.free = free;
    m_resources.append(data);
  }

  /**
   * Construct an object with the same value in the ResourceCollector and return a reference to the
   * new value.
   */
  template<typename T> T &add_value(T &&value, const char *name)
  {
    return this->construct<T>(name, std::forward<T>(value));
  }

  /**
   * Returns a reference to a linear allocator that is owned by the ResourcesCollector. Memory
   * allocated through this allocator will be freed when the collector is destructed.
   */
  LinearAllocator<> &linear_allocator()
  {
    return m_allocator;
  }

  /**
   * Utility method to construct an instance of type T that will be owned by the ResourceCollector.
   */
  template<typename T, typename... Args> T &construct(const char *name, Args &&... args)
  {
    destruct_ptr<T> value_ptr = m_allocator.construct<T>(std::forward<Args>(args)...);
    T &value_ref = *value_ptr;
    this->add(std::move(value_ptr), name);
    return value_ref;
  }

  /**
   * Print the names of all the resources that are owned by this ResourceCollector. This can be
   * useful for debugging.
   */
  void print(StringRef name) const
  {
    if (m_resources.size() == 0) {
      std::cout << "\"" << name << "\" has no resources.\n";
      return;
    }
    else {
      std::cout << "Resources for \"" << name << "\":\n";
      for (const ResourceData &data : m_resources) {
        std::cout << "  " << data.data << ": " << data.debug_name << '\n';
      }
    }
  }
};

}  // namespace blender