Benefits - get rid of yet another pervasive Boost dependency - define additional more fine grained policies (move only, clonable)
226 lines
7.4 KiB
C++
226 lines
7.4 KiB
C++
/*
|
|
STATE-MAP-GROUPING-STORAGE.hpp - grouping storage to track presentation state
|
|
|
|
Copyright (C) Lumiera.org
|
|
2016, 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 state-map-grouping-storage.hpp
|
|
** Implementation of storage for captured presentation state.
|
|
** This is a associative storage, grouped by element ID.
|
|
**
|
|
** @see StateMapGroupingStorage_test
|
|
** @see StateRecorder
|
|
** @see BusTerm_test::captureStateMark()
|
|
** @see BusTerm_test::replayStateMark()
|
|
**
|
|
*/
|
|
|
|
|
|
#ifndef GUI_CTRL_STATE_MAP_GROUPING_STORAGE_H
|
|
#define GUI_CTRL_STATE_MAP_GROUPING_STORAGE_H
|
|
|
|
|
|
#include "lib/error.hpp"
|
|
#include "lib/nocopy.hpp"
|
|
#include "lib/idi/entry-id.hpp"
|
|
#include "lib/diff/gen-node.hpp"
|
|
#include "lib/util.hpp"
|
|
|
|
#include <unordered_map>
|
|
#include <algorithm>
|
|
#include <set>
|
|
|
|
|
|
namespace gui {
|
|
namespace ctrl {
|
|
|
|
using lib::idi::BareEntryID;
|
|
using lib::diff::GenNode;
|
|
using lib::diff::Ref;
|
|
using ::util::unConst;
|
|
using std::string;
|
|
|
|
|
|
|
|
/**
|
|
* Map storage for captured presentation state information.
|
|
* The master table is an association of model::Tangible element IDs
|
|
* to StateData records, which are a set of property data elements.
|
|
* The key of the stored elements acts as propertyKey and was chosen
|
|
* by the originating UI element. It is assumed that the entry last
|
|
* seen represents the current state of this property, so previous
|
|
* records are overwritten. Access to unknown data is marked by
|
|
* returning diff::Ref::NO rsp. `Storage::end()` (when searching)
|
|
* @todo reinvestigate with GCC-5 //////////////////////////////////TICKET #991
|
|
* @see StateMapGroupingStorage_test
|
|
*/
|
|
class StateMapGroupingStorage
|
|
: util::NonCopyable
|
|
{
|
|
using StateData = std::set<GenNode, GenNode::IDComparator>;
|
|
using Storage = std::unordered_map<BareEntryID, StateData, BareEntryID::UseEmbeddedHash>;
|
|
|
|
|
|
Storage elmTable_;
|
|
|
|
public:
|
|
using Record = Storage::value_type;
|
|
|
|
bool
|
|
empty() const
|
|
{
|
|
return elmTable_.empty();
|
|
}
|
|
|
|
size_t
|
|
size() const
|
|
{
|
|
size_t siz{0};
|
|
for (Record const& entry : elmTable_)
|
|
siz += entry.second.size();
|
|
return siz;
|
|
}
|
|
|
|
void
|
|
clear()
|
|
{
|
|
elmTable_.clear();
|
|
}
|
|
|
|
|
|
/** retrieve captured state
|
|
* @return reference to the state mark last seen for the denoted property
|
|
* or reference to a generic "no" marker (Ref::NO)
|
|
*/
|
|
GenNode const&
|
|
retrieve (BareEntryID const& elementID, string propertyKey) const
|
|
{
|
|
iterator entry = find (elementID);
|
|
if (entry == elmTable_.end())
|
|
return Ref::NO;
|
|
else
|
|
return getState (*entry, propertyKey);
|
|
}
|
|
|
|
/** remember the state mark for the denoted element
|
|
* @note stateMark value is assigned to a previously existing
|
|
* entry with the same ID-symbol. If no such entry exists,
|
|
* a (heap allocated) copy of the state mark is stored.
|
|
*/
|
|
void
|
|
record (BareEntryID const& elementID, GenNode const& stateMark)
|
|
{
|
|
auto res = elmTable_[elementID].emplace (stateMark);
|
|
if (not res.second)
|
|
unConst(*res.first) = stateMark; // update existing contents
|
|
}
|
|
|
|
/** clear previously recorded state for a given element and specific property */
|
|
void
|
|
clearProperty (BareEntryID const& elementID, string propertyKey)
|
|
{
|
|
iterator entry = find (elementID);
|
|
if (entry != elmTable_.end())
|
|
{
|
|
StateData const& stateSet = entry->second;
|
|
auto propertyRecord = findProperty(stateSet, propertyKey);
|
|
|
|
if (propertyRecord != stateSet.end())
|
|
unConst(stateSet).erase (propertyRecord);
|
|
}
|
|
}
|
|
|
|
/** clear any previously recorded state for a given element */
|
|
void
|
|
clearState (BareEntryID const& elementID)
|
|
{
|
|
iterator entry = find (elementID);
|
|
if (entry != elmTable_.end())
|
|
elmTable_.erase (entry);
|
|
}
|
|
|
|
|
|
using iterator = Storage::const_iterator;
|
|
|
|
iterator begin() const { return elmTable_.begin(); }
|
|
iterator end() const { return elmTable_.end(); }
|
|
|
|
iterator
|
|
find (BareEntryID const& elementID) const
|
|
{
|
|
return elmTable_.find (elementID);
|
|
}
|
|
|
|
static BareEntryID const&
|
|
getID (Record const& entry)
|
|
{
|
|
return entry.first;
|
|
}
|
|
|
|
static StateData const&
|
|
getState (Record const& entry)
|
|
{
|
|
return entry.second;
|
|
}
|
|
|
|
|
|
/**
|
|
* Access the recorded state mark, if any.
|
|
* @warning we can't search logarithmically,
|
|
* since this would require to construct another GenNode to represent the key.
|
|
* @todo seemingly GCC-4.9 doesn't yet support the "transparent search" feature
|
|
* of C++14, where std::set would support an additional overload of the `find()` function,
|
|
* templated to accept a value _convertible_ to some key equivalent, which needs to be
|
|
* understood by the comparator of the set. To trigger using this overload, the
|
|
* comparator has to define a suitable `operator()` and in addition a marker type
|
|
* `is_transparent`. See [transparent-cmp] and the [reference][cind-cpp14] for explanation.
|
|
* //////////////////////////////////TICKET #991
|
|
* [find-cpp14]: http://en.cppreference.com/w/cpp/container/set/find
|
|
* [transparent-cmp]: http://stackoverflow.com/questions/20317413/what-are-transparent-comparators
|
|
*/
|
|
static GenNode const&
|
|
getState (Record const& entry, string propertyKey)
|
|
{
|
|
StateData const& stateSet = entry.second;
|
|
StateData::const_iterator propertyRecord = findProperty (stateSet, propertyKey);
|
|
|
|
if (propertyRecord == stateSet.end())
|
|
return Ref::NO;
|
|
else
|
|
return *propertyRecord;
|
|
}
|
|
|
|
private:
|
|
static StateData::const_iterator
|
|
findProperty (StateData const& stateSet, string propertyKey)
|
|
{
|
|
return std::find_if (stateSet.begin()
|
|
,stateSet.end()
|
|
,[=](GenNode const& stateMark)
|
|
{
|
|
return propertyKey == stateMark.idi.getSym();
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
|
|
}} // namespace gui::ctrl
|
|
#endif /*GUI_CTRL_STATE_MAP_GROUPING_STORAGE_H*/
|