OwnershipModels.hpp
Go to the documentation of this file.
1 //
3 // Thor C++ Library
4 // Copyright (c) 2011-2016 Jan Haller
5 //
6 // This software is provided 'as-is', without any express or implied
7 // warranty. In no event will the authors be held liable for any damages
8 // arising from the use of this software.
9 //
10 // Permission is granted to anyone to use this software for any purpose,
11 // including commercial applications, and to alter it and redistribute it
12 // freely, subject to the following restrictions:
13 //
14 // 1. The origin of this software must not be misrepresented; you must not
15 // claim that you wrote the original software. If you use this software
16 // in a product, an acknowledgment in the product documentation would be
17 // appreciated but is not required.
18 //
19 // 2. Altered source versions must be plainly marked as such, and must not be
20 // misrepresented as being the original software.
21 //
22 // 3. This notice may not be removed or altered from any source distribution.
23 //
25 
28 
29 #ifndef THOR_OWNERSHIPMODELS_HPP
30 #define THOR_OWNERSHIPMODELS_HPP
31 
32 #include <Thor/Config.hpp>
33 
34 #include <Aurora/Meta/Templates.hpp>
35 
36 #include <memory>
37 #include <cassert>
38 
39 
40 namespace thor
41 {
42 
45 
46 namespace Resources
47 {
48 
56  struct CentralOwner {};
57 
64  struct RefCounted {};
65 
66 } // namespace Resources
67 
69 
70 // ---------------------------------------------------------------------------------------------------------------------------
71 
72 
73 namespace detail
74 {
75 
76  template <typename Map>
77  struct ElementRef
78  {
79  Map* map;
80  typename Map::iterator itr;
81  };
82 
83  template <typename Map>
84  ElementRef<Map> makeElementRef(Map& map, typename Map::iterator itr)
85  {
86  // Aggregate syntax instead of return {...}; to support older compilers and work around compiler bug in VS 2016 RC
87  ElementRef<Map> ref = {&map, itr};
88  return ref;
89  }
90 
91  template <typename R, typename Map>
92  struct TrackingDeleter
93  {
94  void operator() (R* pointer)
95  {
96  // If map element exists, erase it
97  if (!tracker.expired())
98  {
99  // Verify resource ID is still there
100  assert(element.map->find(element.itr->first) != element.map->end());
101  element.map->erase(element.itr);
102  }
103 
104  // Perform actual deallocation
105  AURORA_REQUIRE_COMPLETE_TYPE(R);
106  delete pointer;
107  }
108 
109  ElementRef<Map> element;
110  std::weak_ptr<char> tracker;
111  };
112 
113  // Class to dispatch between ownership model, using partial template specialization
114  template <typename Model, typename R>
115  struct OwnershipModel;
116 
117  // Specialization for centralized ownership (user only holds references)
118  template <typename R>
119  struct OwnershipModel<Resources::CentralOwner, R>
120  {
121  typedef R& Returned;
122  typedef const R& ConstReturned;
123  typedef std::unique_ptr<R> Loaded;
124  typedef std::unique_ptr<R> Stored;
125 
126  static Returned makeReturned(const std::unique_ptr<R>& initialOrStorage)
127  {
128  return *initialOrStorage;
129  }
130 
131  template <typename Map>
132  static std::unique_ptr<R> makeLoaded(std::unique_ptr<R>&& resource, ElementRef<Map>&&)
133  {
134  return std::move(resource);
135  }
136 
137  static std::unique_ptr<R> makeStored(std::unique_ptr<R>&& loaded)
138  {
139  return std::move(loaded);
140  }
141  };
142 
143  // Specialization for reference-counted ownership
144  template <typename R>
145  struct OwnershipModel<Resources::RefCounted, R>
146  {
147  typedef std::shared_ptr<R> Returned;
148  typedef std::shared_ptr<const R> ConstReturned;
149 
150  // First object being constructed directly from resource.
151  // Prepares tracking semantics
152  struct Loaded
153  {
154  std::shared_ptr<char> tracked;
155  std::shared_ptr<R> resource;
156  };
157 
158  // Map's value type, stores weak pointer to resource and eraser to remove itself from map
159  // Can potentially be optimized by avoiding indirect call through std::function
160  struct Stored
161  {
162  std::shared_ptr<char> tracked;
163  std::weak_ptr<R> resource;
164  };
165 
166  static std::shared_ptr<R> makeReturned(const Loaded& loaded)
167  {
168  return loaded.resource;
169  }
170 
171  static std::shared_ptr<R> makeReturned(const Stored& stored)
172  {
173  assert(!stored.resource.expired());
174  return std::shared_ptr<R>(stored.resource); // shouldn't throw after assert
175  }
176 
177  template <typename Map>
178  static Loaded makeLoaded(std::unique_ptr<R>&& resource, ElementRef<Map>&& element)
179  {
180  // Tracked object: shared pointer referenced by multiple weak pointers.
181  // If object holding tracked dies, all weak_ptr objects become expired.
182  auto tracked = std::make_shared<char>();
183 
184  // Deleter for shared_ptr. Users will hold shared_ptrs with this deleter, so
185  // the last one will erase the element from the map.
186  TrackingDeleter<R, Map> deleter;
187  deleter.tracker = tracked;
188  deleter.element = element;
189 
190  // Create initial object that holds the resource as well as a strong tracked shared_ptr
191  Loaded loaded;
192  loaded.tracked = std::move(tracked);
193  loaded.resource = std::shared_ptr<R>(resource.release(), deleter);
194  return loaded;
195  }
196 
197  static Stored makeStored(Loaded&& loaded)
198  {
199  Stored stored;
200  stored.tracked = std::move(loaded.tracked);
201  stored.resource = std::weak_ptr<R>(loaded.resource);
202  return stored;
203  }
204  };
205 
206 } // namespace detail
207 } // namespace thor
208 
209 #endif // THOR_OWNERSHIPMODELS_HPP
Definition: AnimationMap.hpp:42
Configuration header of the library.
Centralized ownership policy.
Definition: OwnershipModels.hpp:56
Reference-counted ownership policy.
Definition: OwnershipModels.hpp:64