Path.hpp
1 #pragma once
2 #include <score/document/DocumentInterface.hpp>
3 #include <score/tools/Metadata.hpp>
4 
8 template <typename T, typename U>
10 {
11  static const constexpr bool value
12  = std::is_base_of<T, U>::value || std::is_base_of<U, T>::value;
13 };
14 
15 // These forward declarations are required
16 // because Path<T>(Object&) calls score::IDocument::path()
17 // which in turns calls another constructor of Path<T>.
18 template <typename Object>
19 class Path;
20 template <typename T>
21 class IdentifiedObject;
22 
23 namespace score
24 {
25 class DocumentPlugin;
26 namespace IDocument
27 {
28 template <typename T>
29 Path<T> path(const IdentifiedObject<T>& obj);
30 }
31 }
32 
50 template <typename Object>
51 class Path
52 {
53  friend bool operator==(const Path& lhs, const Path& rhs) noexcept
54  {
55  return lhs.m_impl == rhs.m_impl;
56  }
57 
58  friend bool operator!=(const Path& lhs, const Path& rhs) noexcept
59  {
60  return lhs.m_impl != rhs.m_impl;
61  }
62 
63  friend uint qHash(const Path& obj, uint seed) noexcept
64  {
65  return qHash(obj.m_impl, seed);
66  }
67 
68  template <typename U>
69  friend class Path;
70  friend class ObjectPath;
71 
72 public:
79  {
80  UnsafeDynamicCreation() = default;
81  };
82 
83  Path(const ObjectPath& obj, UnsafeDynamicCreation) noexcept
84  : m_impl{obj.vec()}
85  {
86  }
87  Path(ObjectPath&& obj, UnsafeDynamicCreation) noexcept
88  : m_impl{std::move(obj.vec())}
89  {
90  }
91 
92  Path(const Object& obj) noexcept
93  : Path(score::IDocument::path(obj))
94  {
95  }
96 
97  ~Path() = default;
98 
100  template <typename U>
101  auto extend(const QString& name, const Id<U>& id) const& noexcept
102  {
103  Path<U> p{this->m_impl.vec()};
104  p.m_impl.vec().push_back({name, id});
105  return p;
106  }
107 
110  template <typename U>
111  auto extend(const QString& name, const Id<U>& id) && noexcept
112  {
113  Path<U> p{std::move(this->m_impl.vec())};
114  p.m_impl.vec().push_back({name, id});
115  return p;
116  }
117 
119  template <typename U>
120  auto extend(const Id<U>& id) const& noexcept
121  {
122  Path<U> p{this->m_impl.vec()};
123  p.m_impl.vec().push_back({Metadata<ObjectKey_k, U>::get(), id});
124  return p;
125  }
126 
129  template <typename U>
130  auto extend(const Id<U>& id) && noexcept
131  {
132  Path<U> p{std::move(this->m_impl.vec())};
133  p.m_impl.vec().push_back({Metadata<ObjectKey_k, U>::get(), id});
134  return p;
135  }
136 
138  template <typename U>
139  auto splitLast() const&
140  {
141  SCORE_ASSERT(m_impl.vec().size() > 0);
142  auto vec = m_impl.vec();
143  auto last = vec.back();
144  vec.pop_back();
145  return std::make_pair(Path<U>{std::move(vec)}, std::move(last));
146  }
147 
150  template <typename U>
151  auto splitLast() &&
152  {
153  // Note : we *must not* move directly m_impl
154  // because it carries a cache that becomes wrong.
155  SCORE_ASSERT(!m_impl.vec().empty());
156  auto last = m_impl.vec().back();
157  m_impl.vec().pop_back();
158  return std::make_pair(Path<U>{std::move(m_impl.vec())}, std::move(last));
159  }
160 
161  // TODO do the same for ids
162  // TODO make it work only for upcasts
163  template <typename U>
165  Path(const Path<U>& other) noexcept
166  : m_impl{other.m_impl.vec()}
167  {
168  }
169 
170  template <typename U>
172  Path(Path<U>&& other) noexcept
173  : m_impl{std::move(other.m_impl.vec())}
174  {
175  }
176 
177  template <typename U>
179  Path& operator=(const Path<U>& other) noexcept
180  {
181  m_impl = other.m_impl;
182  return *this;
183  }
184 
185  template <typename U>
187  Path& operator=(Path<U>&& other) noexcept
188  {
189  m_impl = std::move(other.m_impl);
190  return *this;
191  }
192 
193  Path() noexcept = default;
194  Path(const Path&) noexcept = default;
195  Path(Path&&) noexcept = default;
196  Path& operator=(const Path&) noexcept = default;
197  Path& operator=(Path&&) noexcept = default;
198 
199  Object& find(const score::DocumentContext& ctx) const
200  {
201  SCORE_ASSERT(valid());
202  return m_impl.find<Object>(ctx);
203  }
204  Object* try_find(const score::DocumentContext& ctx) const noexcept
205  {
206  if(!valid())
207  return nullptr;
208  return m_impl.try_find<Object>(ctx);
209  }
210 
211  const auto& unsafePath() const& noexcept { return m_impl; }
212  auto& unsafePath() & noexcept { return m_impl; }
213  auto&& unsafePath() && noexcept { return std::move(m_impl); }
214 
215  bool valid() const noexcept { return !m_impl.vec().empty(); }
216 
217 private:
218  Path(const ObjectPath& path) noexcept
219  : m_impl{path.vec()}
220  {
221  }
222  Path(ObjectPath&& path) noexcept
223  : m_impl{std::move(path.vec())}
224  {
225  }
226  Path(const std::vector<ObjectIdentifier>& vec) noexcept
227  : m_impl{vec}
228  {
229  }
230  Path(std::vector<ObjectIdentifier>&& vec) noexcept
231  : m_impl{std::move(vec)}
232  {
233  }
234 
235  ObjectPath m_impl;
236 };
237 
238 template <typename T>
239 Path<T> make_path(const T& t)
240 {
241  return t;
242 }
243 namespace std
244 {
245 template <typename tag>
246 struct hash<Path<tag>>
247 {
248  std::size_t operator()(const Path<tag>& path) const
249  {
250  return std::hash<ObjectPath>{}(path.unsafePath());
251  }
252 };
253 }
254 
255 namespace score
256 {
257 template <typename T>
258 auto id(const Path<T>& path)
259 {
260  SCORE_ASSERT(path.valid());
261  SCORE_ASSERT(bool(path.unsafePath().vec().back().id()));
262 
263  return Id<T>(path.unsafePath().vec().back().id());
264 }
265 }
The IdentifiedObject class.
Definition: IdentifiedObject.hpp:19
The ObjectPath class.
Definition: ObjectPath.hpp:37
T * try_find(const score::DocumentContext &ctx) const noexcept
Tries to find an object.
Definition: ObjectPath.hpp:131
T & find(const score::DocumentContext &ctx) const
find the object described by the ObjectPath
Definition: ObjectPath.hpp:110
The Path class is a typesafe wrapper around ObjectPath.
Definition: Path.hpp:52
auto extend(const QString &name, const Id< U > &id) &&noexcept
Definition: Path.hpp:111
auto splitLast() &&
Definition: Path.hpp:151
auto extend(const Id< U > &id) &&noexcept
Definition: Path.hpp:130
auto splitLast() const &
Return a new path without the last element of this one.
Definition: Path.hpp:139
auto extend(const QString &name, const Id< U > &id) const &noexcept
Add a new ObjectIdentifier at the end of the path and return a new path.
Definition: Path.hpp:101
auto extend(const Id< U > &id) const &noexcept
Add a new ObjectIdentifier at the end of the path and return a new path.
Definition: Path.hpp:120
The id_base_t class.
Definition: Identifier.hpp:57
Base toolkit upon which the software is built.
Definition: Application.cpp:90
Static metadata implementation.
Definition: lib/score/tools/Metadata.hpp:36
Use this if it is not possible to get a path.
Definition: Path.hpp:79
Used to know if two types are in an inheritance relationship.
Definition: Path.hpp:10
Definition: DocumentContext.hpp:18
Definition: ObjectPath.hpp:186