Lumiera  0.pre.03
»edit your freedom«
scope-path.cpp
Go to the documentation of this file.
1 /*
2  ScopePath - logical access path down from Session root
3 
4  Copyright (C) Lumiera.org
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
30 #include "include/logging.h"
35 #include "lib/itertools.hpp"
36 #include "lib/symbol.hpp"
37 #include "lib/error.hpp"
38 #include "lib/util.hpp"
39 
40 #include <algorithm>
41 
42 namespace steam {
43 namespace mobject {
44 namespace session {
45 
46  using std::reverse;
47  using lib::append_all;
48  using util::isSameObject;
49  using util::isnil;
50 
51 
52  namespace { // Helpers and shortcuts....
53 
57  discoverScopePath (Scope const& leaf)
58  {
59  return ScopeLocator::instance().getRawPath (leaf);
60  }
61 
62 
63  void
64  ___check_notBottom (const ScopePath *path, lib::Literal operation_descr)
65  {
66  REQUIRE (path);
67  if (path->empty())
68  throw error::Logic (operation_descr+" an empty placement scope path"
69  , LERR_(EMPTY_SCOPE_PATH));
70  }
71  }//(End) helpers
72 
73 
74 
75 
84  : refcount_(0)
85  , path_()
86  {
87  clear();
88  }
89 
90 
102  : refcount_(0)
103  , path_()
104  {
105  if (leaf == Scope::INVALID) return; // invalid leaf defines invalid path....
106 
107  clear();
108  navigate (leaf);
109  }
110 
111 
113  : refcount_(0)
114  , path_(o.path_)
115  { }
116 
121  ScopePath&
123  {
124  if (0 < refcount_)
125  throw error::Logic ("Attempt to overwrite a ScopePath with nonzero refcount");
126 
127  if (!isSameObject (*this, ref))
128  {
129  path_ = ref.path_;
130  ENSURE (0 == refcount_);
131  }
132  return *this;
133  }
134 
135 
136  ScopePath::~ScopePath()
137  {
138  WARN_IF (refcount_, session, "Destroying a scope path frame with ref-count=%zu", refcount_);
139  }
140 
141 
144 
145 
150  ScopePath::operator string() const
151  {
152  if (isnil (path_)) return "!";
153  if (1 == length()) return "/";
154 
155  string res;
156  vector<Scope>::const_iterator node (path_.begin());
157  while (++node != path_.end())
158  {
159  res += "/";
160  res += string (*node);
161  }
162  return res;
163  }
164 
165 
169  bool
171  {
172  return (1 < length())
173 #if NOBUG_MODE_ALPHA
174  && hasValidRoot()
175 #endif
176  ;
177  }
178 
179  bool
180  ScopePath::hasValidRoot() const
181  {
182  REQUIRE (0 < length());
183  return path_[0] == currModelRoot();
184  }
185 
186  PlacementMO const&
187  ScopePath::currModelRoot() const
188  {
190  }
191 
192 
193 
194 
195 
196  /* == Relations == */
197 
198  Scope const&
199  ScopePath::getLeaf() const
200  {
201  ___check_notBottom (this, "Inspecting");
202  return path_.back();
203  }
204 
205 
211  bool
212  ScopePath::endsAt(Scope const& aScope) const
213  {
214  return aScope == getLeaf();
215  }
216 
217 
218  bool
219  ScopePath::contains (Scope const& aScope) const
220  {
221  if (aScope == Scope::INVALID) return true; // bottom is contained everywhere
222 
223  for (iterator ii = this->begin(); ii; ++ii)
224  if (aScope == *ii)
225  return true;
226 
227  return false;
228  }
229 
230 
231  bool
232  ScopePath::contains (ScopePath const& otherPath) const
233  {
234  if (!otherPath.isValid()) return true;
235  if ( empty()) return false;
236  if (!isValid()) return false;
237 
238  ASSERT (1 < length());
239  ASSERT (1 < otherPath.length());
240 
241  for (iterator ii = otherPath.begin(); ii; ++ii)
242  if (!this->contains (*ii))
243  return false;
244 
245  return true;
246  }
247 
248 
249  ScopePath
250  commonPrefix (ScopePath const& path1, ScopePath const& path2)
251  {
252  ScopePath prefix (ScopePath::INVALID);
253  uint len = std::min (path1.length(), path2.length());
254  for (uint pos = 0; pos<len; ++pos)
255  if (path1.path_[pos] == path2.path_[pos])
256  prefix.appendScope (path1.path_[pos]);
257 
258  return prefix;
259  }
260 
261  bool
262  disjoint (ScopePath const& path1, ScopePath const& path2)
263  {
264  if (path1.empty() || path2.empty()) return false;
265 
266  return (path1.isValid() && path2.isValid())
267  && (path1.path_[1] != path2.path_[1]) // no common prefix
268  ;
269  }
270 
271 
272 
273 
274  /* == Mutations == */
275 
276  void
277  ScopePath::clear()
278  {
279  path_.clear();
280  path_.push_back (currModelRoot());
281 
282  ENSURE (!empty());
283  ENSURE (!isValid());
284  ENSURE ( hasValidRoot());
285  }
286 
287 
288  Scope const&
289  ScopePath::moveUp()
290  {
291  ___check_notBottom (this, "Navigating");
292 
293  path_.resize (length()-1);
294 
295  if (empty()) return Scope::INVALID;
296  else return path_.back();
297  }
298 
299 
300  Scope const&
301  ScopePath::goRoot()
302  {
303  ___check_notBottom (this, "Navigating");
304  ENSURE (hasValidRoot());
305 
306  path_.resize (1);
307  return path_.back();
308  }
309 
310 
311  void
312  ScopePath::navigate (Scope const& target)
313  {
314  ___check_notBottom (this, "Navigating");
315  if (!target.isValid())
316  throw error::Invalid ("can't navigate to a target scope outside the model"
317  , LERR_(INVALID_SCOPE));
318 
319  std::vector<Scope> otherPath;
320  append_all (discoverScopePath(target), otherPath);
321  reverse (otherPath.begin(), otherPath.end());
323  ASSERT (path_[0] == otherPath[0]); // sharing the root element
324  this->path_ = otherPath; // TODO really relate the two paths, including a treatment for meta-clips
325  // - if both are in the same sequence (same head element): just attach the tail of the other
326  // - if the other path points into a sequence which is attached as meta-clip to the current sequence,
327  // then attach the other path below that meta-clip (problem: resolve multiple attachments)
328  // - otherwise use the first timeline, to which the other path's sequence is attached
329  // - otherwise, if all else fails, use the raw otherPath
330  }
331 
332 
333  void
335  {
336  path_.push_back (child);
337  }
338 
339 
340 
341 
342 
343 }}} // namespace mobject::session
Implementation level session API: query a scope.
ScopePath & operator=(ScopePath const &)
Copy from existing path.
Definition: scope-path.cpp:122
bool endsAt(Scope const &) const
verify the scope in question is equivalent to our leaf scope.
Definition: scope-path.cpp:212
bool empty() const
an empty path doesn&#39;t even contain a root element.
Definition: scope-path.hpp:265
static const ScopePath INVALID
constant invalid path token.
Definition: scope-path.hpp:153
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
ScopeQuery< MObject >::iterator discoverScopePath(Scope const &leaf)
issue a query to discover the (raw) path to root, starting with the given scope
Definition: scope-path.cpp:57
This header is for including and configuring NoBug.
Core abstraction of the Session model: a media object.
Steam-Layer implementation namespace root.
Namespace of Session and user visible high-level objects.
Definition: sequence.hpp:74
Sequence of nested scopes within the high-level model.
Definition: scope-path.hpp:135
A Placement scope within the high-level-model.
Definition: scope.hpp:78
bool isValid() const
check if this scope can be located.
Definition: scope.cpp:240
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
Marker types to indicate a literal string and a Symbol.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
bool isValid() const
a valid path consists of more than just the root element.
Definition: scope-path.cpp:170
static const Scope INVALID
constant invalid scope token.
Definition: scope.hpp:92
Lumiera error handling (C++ interface).
Service to build the notion of a current location within the Sesison model.
An Object representing a sequence of nested scopes within the Session.
static lib::Depend< ScopeLocator > instance
Storage holding the single ScopeLocator instance.
Helpers for working with iterators based on the pipeline model.
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
Adapter for building an implementation of the »Lumiera Forward Iterator« concept. ...
ScopePath()
Create an empty path.
Definition: scope-path.cpp:83
bool isSameObject(A const &a, B const &b)
compare plain object identity, bypassing any custom comparison operators.
Definition: util.hpp:372