LUMIERA.clone/src/steam/mobject/session/query-focus-stack.hpp
Ichthyostega acb674a9d2 Project: update and clean-up Doxygen configuration
...in an attempt to clarify why numerous cross links are not generated.
In the end, this attempt was not very successful, yet I could find some breadcrumbs...

- file comments generally seem to have a problem with auto link generation;
  only fully qualified names seem to work reliably

- cross links to entities within a namespace do not work,
  if the corresponding namespace is not documented in Doxygen

- documentation for entities within anonymous namespaces
  must be explicitly enabled. Of course this makes only sense
  for detailed documentation (but we do generate detailed
  documentation here, including implementation notes)

- and the notorious problem: each file needs a valid @file comment

- the hierarchy of Markdown headings must be consistent within each
  documentation section. This entails also to individual documented
  entities. Basically, there must be a level-one heading (prefix "#"),
  otherwise all headings will just disappear...

- sometimes the doc/devel/doxygen-warnings.txt gives further clues
2021-01-24 19:35:45 +01:00

203 lines
5.1 KiB
C++

/*
QUERY-FOCUS-STACK.hpp - management of current scope within the Session
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file query-focus-stack.hpp
** Implementation facility to work with and navigate nested scopes
** @todo WIP implementation of session core from 2010
** @todo as of 2016, this effort is considered stalled but basically valid
*/
#ifndef MOBJECT_SESSION_QUERY_FOCUS_STACK_H
#define MOBJECT_SESSION_QUERY_FOCUS_STACK_H
#include "steam/mobject/session/scope-path.hpp"
#include "lib/nocopy.hpp"
#include <list>
using std::list;
namespace steam {
namespace mobject {
namespace session {
/**
* A custom stack holding ScopePath »frames«.
* It is utilised by the ScopeLocator to establish the
* \em current query focus location. Client code should
* access this mechanism through QueryFocus instances
* used as frontend. These QueryFocus objects incorporate
* a boost::intrusive_ptr, which stores the ref-count within
* the mentioned ScopePath frames located in the stack.
*
* \par automatic cleanup of unused frames
* The stack is aware of this ref-counting mechanism and will --
* on each access -- automatically clean up any unused frames starting
* from stack top, until encountering the first frame still in use.
* This frame, by definition, is the <b>current focus location</b>.
* The stack ensures there is always at least one ScopePath frame,
* default-creating a new one if necessary.
*
* @see query-focus-stack-test.cpp
* @see ScopeLocator
* @see QueryFocus access point for client code
*/
class QueryFocusStack
: util::NonCopyable
{
std::list<ScopePath> paths_;
public:
QueryFocusStack ()
: paths_()
{
openDefaultFrame();
}
bool empty () const;
size_t size () const;
ScopePath& push (Scope const&);
ScopePath& top ();
void pop_unused ();
void clear ();
private:
void openDefaultFrame ();
};
/* __implementation__ */
bool
QueryFocusStack::empty () const
{
return paths_.empty();
}
size_t
QueryFocusStack::size () const
{
return paths_.size();
}
void
QueryFocusStack::clear ()
{
paths_.clear();
openDefaultFrame();
}
/** Open a new path frame, pushing down the current frame.
* The new frame tries to locate the given start scope
* and navigates to this position.
* @note EXCEPTION_STRONG guarantee
* @return reference to the newly created path on top
* @throw error::Invalid if newStartPoint isn't locatable
*/
ScopePath&
QueryFocusStack::push (Scope const& newStartPoint)
{
ScopePath newPathFrame (newStartPoint); // may throw
ENSURE (newPathFrame.isValid() || newStartPoint.isRoot());
paths_.push_back (newPathFrame);
ENSURE (0 < size());
return paths_.back();
}
/** @return the topmost path frame actually in use
* @note may invoke #pop_unused()
* @note EXCEPTON_FREE ///////TODO prove!
*/
ScopePath&
QueryFocusStack::top ()
{
if ( 0 == size()
|| 0 == paths_.back().ref_count()
)
pop_unused();
ENSURE (!empty());
return paths_.back();
}
/** investigate the stack top and discard any path frames
* which aren't referred anymore (as indicated by their
* ScopePath#use_count(). After executing this function
* the topmost frame is either in use, or a new default
* frame has been created at the bottom of an empty stack.
* @note EXCEPTION_FREE ///////TODO prove!
*/
void
QueryFocusStack::pop_unused ()
{
if (1 == size() && !paths_.front().isValid())
return; // unnecessary to evict a base frame repeatedly
while (size() && (0 == paths_.back().ref_count()))
paths_.pop_back();
if (0 == size())
openDefaultFrame();
ENSURE (!empty());
}
/** @internal open a default path frame at the bottom
* of an empty stack, locating to current model root
* @note EXCEPTION_FREE ///////TODO prove!
*/
void
QueryFocusStack::openDefaultFrame ()
{
REQUIRE (0 == size());
paths_.resize(1);
ENSURE (!paths_.front().empty());
ENSURE (!paths_.front().isValid()); // i.e. just root scope
}
}}} // namespace mobject::session
#endif /*MOBJECT_SESSION_QUERY_FOCUS_STACK_H*/