UI-Coordinates: implement path split and appending of multiple components

Unit test passes thus far
This commit is contained in:
Fischlurch 2017-10-02 04:04:22 +02:00
parent 835b964e63
commit 286b1829fe
4 changed files with 113 additions and 37 deletions

View file

@ -57,7 +57,9 @@
#include "lib/util.hpp"
//#include <boost/noncopyable.hpp>
#include <cstring>
#include <string>
#include <vector>
#include <utility>
//#include <memory>
@ -134,7 +136,7 @@ namespace interact {
// convenience shortcuts to start mutation on a copy...
Builder path (string pathDefinition) const;
Builder path (Literal pathDefinition) const;
Builder append (Literal elmID) const;
Builder prepend (Literal elmID) const;
@ -257,6 +259,13 @@ namespace interact {
/** @note Builder allowed to manipulate stored data */
friend class Builder;
size_t
findStartIdx() const
{
REQUIRE (not empty());
return indexOf (*begin());
}
Literal
accesComponent (UIPathElm idx) const
{
@ -267,15 +276,68 @@ namespace interact {
void
setComponent (size_t idx, Literal newContent)
{
Literal* storage = maybeExpandTo (idx);
Literal* storage = expandPosition (idx);
setContent (storage, newContent);
}
size_t
findStartIdx() const
/** replace / overwrite existing content starting at given index.
* @param idx where to start adding content; storage will be expanded to accommodate
* @param newContent either a single element, or several elements delimited by `'/'`
* @note - a path sequence will be split at `'/'` and the components _interned_
* - any excess elements will be cleared
* @warning need to invoke PathArray::normalise() afterwards
*/
void
setTailSequence (size_t idx, Literal newContent)
{
REQUIRE (not empty());
return indexOf (*begin());
std::vector<Literal> elms;
if (not isnil (newContent))
{
if (not std::strchr (newContent, '/'))
{
// single element: just place it as-is
// and remove any further content behind
elms.emplace_back (newContent);
}
else
{ // it is actually a sequence of elements,
// which need to be split first, and then
// interned into the global symbol table
string sequence{newContent};
size_t pos = 0;
size_t last = 0;
while (string::npos != (last = sequence.find ('/', pos)))
{
elms.emplace_back (Symbol{sequence.substr(pos, last - pos)});
pos = last + 1;
}
sequence = sequence.substr(pos);
if (not isnil (sequence))
elms.emplace_back (Symbol{sequence});
} }
setTailSequence (idx, elms);
}
/** replace the existing path information with the given elements
* @note - storage will possibly be expanded to accommodate
* - the individual path elements will be _interned_ as Symbol
* - any excess elements will be cleared
* - the pathElms can be _empty_ in which case just
* any content starting from `idx` will be cleared
* @warning need to invoke PathArray::normalise() afterwards
*/
void
setTailSequence (size_t idx, std::vector<Literal>& pathElms)
{
size_t cnt = pathElms.size();
expandPosition (idx + cnt);
for (size_t i=0 ; i < cnt; ++i)
setContent (expandPosition(idx + i), pathElms[i]);
size_t end = size();
for (size_t i = idx+cnt; i<end; ++i)
setContent (expandPosition(i), nullptr);
}
@ -361,11 +423,15 @@ namespace interact {
}
/** augment UI coordinates by appending a further component at the end */
/** augment UI coordinates by appending a further component at the end.
* @note the element might define a sequence of components separated by `'/'`,
* in which case several elements will be appended.
*/
Builder
append (Literal elmID)
append (Literal elm)
{
uic_.setComponent (uic_.size(), elmID);
if (not isnil(elm))
uic_.setTailSequence (uic_.size(), elm);
return std::move (*this);
}
@ -381,11 +447,16 @@ namespace interact {
return std::move (*this);
}
/** augment UI coordinates to define a complete local path */
/**
* augment UI coordinates to define a complete local path
* @param pathDef a path, possibly with multiple components separated by `'/'`
* @note any existing path definition is completely replaced by the new path
*/
Builder
path (string pathDefinition)
path (Literal pathDef)
{
UNIMPLEMENTED ("set path");
uic_.setTailSequence (UIC_PART, pathDef);
return std::move (*this);
}
};
@ -448,7 +519,7 @@ namespace interact {
* resulting components will be stored/retrieved as Symbol
*/
inline UICoord::Builder
UICoord::path (string pathDefinition) const
UICoord::path (Literal pathDefinition) const
{
return Builder(*this).path (pathDefinition);
}

View file

@ -201,14 +201,19 @@ namespace lib {
resizeTo (size_t cnt)
{
if (cnt > size())
{ // copy to expanded storage
auto target = new const char* [cnt+1];
auto pos = std::copy (storage_, storage_+1+size(), target);
for ( ; pos < target+1+cnt; ++pos)
*pos = nullptr;
{ // need more storage
if (storage_)
delete[] storage_;
storage_ = reinterpret_cast<PStorage> (target);
{ // copy content to new expanded storage
auto target = new const char* [cnt+1];
auto pos = std::copy (storage_, storage_+1+size(), target);
for ( ; pos < target+1+cnt; ++pos)
*pos = nullptr;
delete[] storage_;
storage_ = reinterpret_cast<PStorage> (target);
}
else // allocate and init empty
storage_ = new Literal [cnt+1];
size (storage_) = cnt;
return;
}
@ -453,7 +458,7 @@ namespace lib {
* @return pointer to the storage, either existing or reallocated
*/
Literal*
maybeExpandTo (size_t idx)
expandPosition (size_t idx)
{
if (chunk_size <= idx and size() <= idx)
tail_.resizeTo(idx+1 - chunk_size);

View file

@ -275,23 +275,23 @@ namespace test {
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.prepend("perspective");
CHECK ("UI:UI:?[perspective]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("UI:?[perspective]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?[perspective]-panel.*. " == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.prepend("win");
CHECK ("UI:UI:win[perspective]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("UI:win[perspective]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("win[perspective]-panel.*. " == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.persp("");
CHECK ("UI:UI:win[*]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("UI:win[*]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
CHECK (12 == uic.size());
uic = uic.path(" ");
CHECK ("UI:UI:win[*]-panel.*. / " == string(uic));
CHECK ("UI:win[*]-panel.*. / " == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK (" " == uic.getPath());
CHECK (6 == uic.size());
@ -299,39 +299,39 @@ namespace test {
VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PART+1]);
uic = uic.path(nullptr);
CHECK ("UI:UI:win[*]-panel.*. " == string(uic));
CHECK ("UI:win[*]-panel.*. " == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("" == uic.getPath());
CHECK (5 == uic.size());
VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PART]);
uic = uic.append(nullptr);
CHECK ("UI:UI:win[*]-panel.*. " == string(uic));
CHECK ("UI:win[*]-panel.*. " == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("" == uic.getPath());
CHECK (5 == uic.size());
uic = uic.append("*");
CHECK ("UI:UI:win[*]-panel.*. " == string(uic));
CHECK ("UI:win[*]-panel.*. " == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("" == uic.getPath());
CHECK (5 == uic.size());
uic = uic.append("**");
CHECK ("UI:UI:win[*]-panel.*. /**" == string(uic));
CHECK ("UI:win[*]-panel.*. /**" == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("**" == uic.getPath());
CHECK ("**" == uic[UIC_PART]);
CHECK (6 == uic.size());
uic = uic.tab("");
CHECK ("UI:UI:win[*]-panel.*.*/**" == string(uic));
CHECK ("UI:win[*]-panel.*.*/**" == string(uic));
CHECK ("win[*]-panel.*.*" == uic.getComp());
CHECK ("**" == uic.getPath());
CHECK (6 == uic.size());
uic = uic.path("");
CHECK ("UI:UI:win[*]-panel" == string(uic));
CHECK ("UI:win[*]-panel" == string(uic));
CHECK ("win[*]-panel" == uic.getComp());
CHECK ("" == uic.getPath());
CHECK (3 == uic.size());

View file

@ -3914,13 +3914,13 @@
<node COLOR="#338800" CREATED="1506887647152" ID="ID_1069521621" MODIFIED="1506887654873" TEXT="String representation">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506906671372" ID="ID_458222870" MODIFIED="1506906680445" TEXT="Builder">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1506906671372" ID="ID_458222870" MODIFIED="1506919618620" TEXT="Builder">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1506906657270" ID="ID_1234040290" MODIFIED="1506906687339" TEXT="builder functions">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506906664501" ID="ID_1257993809" MODIFIED="1506906689283" TEXT="mutator functions">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1506906664501" ID="ID_1257993809" MODIFIED="1506919612697" TEXT="mutator functions">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506181727069" ID="ID_467120404" MODIFIED="1506181737140" TEXT="lokale Pr&#xe4;dikate">
@ -3976,8 +3976,8 @@
<node COLOR="#338800" CREATED="1506182009518" ID="ID_138248232" MODIFIED="1506906630089" TEXT="verify_basics">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009519" ID="ID_1637725534" MODIFIED="1506906649946" TEXT="verify_builder">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1506182009519" ID="ID_1637725534" MODIFIED="1506919626951" TEXT="verify_builder">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009519" ID="ID_542761230" MODIFIED="1506182101802" TEXT="verify_comparisons">
<icon BUILTIN="flag-yellow"/>