Value iteration take 3

This commit is contained in:
Michael Davidsaver
2020-07-18 19:39:38 -07:00
parent 0e972ecc71
commit 06e26a0ec5
3 changed files with 284 additions and 166 deletions
+153 -82
View File
@@ -609,7 +609,7 @@ void Value::copyIn(const void *ptr, StoreType type)
// copy struct to struct
// all marked source field may be mapped to destination fields
for(auto& sfld : src.imarked()) {
for(const auto& sfld : src.imarked()) {
if(sfld.type()==TypeCode::Struct) {
// entire sub-struct marked.
@@ -864,84 +864,131 @@ size_t Value::nmembers() const
}
}
void Value::_iter_fl(Value::IterInfo &info, bool first) const
template<>
Value::Iterable<Value::_IAll>::iterator
Value::Iterable<Value::_IAll>::end() const noexcept
{
if(!desc || (desc->code!=TypeCode::Struct && desc->code!=TypeCode::Union)) {
// not iterable
info.pos = info.nextcheck = 0u;
return;
}
// Union iteration has no depth
if(desc->code.scalarOf()!=TypeCode::Struct)
info.depth = false;
// array instances have no marking
if(desc->code.isarray())
info.marked = false;
size_t cnt;
if(info.depth)
cnt = desc->mlookup.size();
else
cnt = desc->miter.size();
info.pos = first ? 0 : cnt;
if(first && info.marked) {
info.nextcheck = info.pos;
_iter_advance(info);
} else {
info.nextcheck = cnt+1; // for !marked, never need to check
iterator ret{val, 0u};
if(val && val.type()==TypeCode::Struct) {
ret.pos = val.desc->mlookup.size();
} else if(val && val.type()==TypeCode::Union) {
ret.pos = val.desc->miter.size();
}
return ret;
}
void Value::_iter_advance(IterInfo& info) const
template<>
Value
Value::_Iterator<Value::_IAll>::operator*() const noexcept
{
assert(desc);
assert(info.marked); // should not be reached for simple iteration
Value ret;
// for Struct, scan to next marked field
if(desc->code==TypeCode::Struct) {
assert(info.depth); // the following assume
if(val.type()==TypeCode::Struct) {
decltype (ret.store) store(val.store, val.store.get() + 1u + pos);
ret.store = std::move(store);
ret.desc = val.desc + 1u + pos;
// scan forward to find next non-marked
for(auto idx : range(info.pos, desc->mlookup.size())) {
auto S = store.get() + idx + 1u;
} else if(val && val.type()==TypeCode::Union) {
auto pos_desc = &val.desc->members[val.desc->miter[pos].second];
if(val.store->as<Value>().desc==pos_desc) {
// pointing to selected Union field
ret = val.store->as<Value>();
} else {
std::shared_ptr<const FieldDesc> base(val.store, pos_desc);
ret = Value(base);
}
}
return ret;
}
template<>
Value::Iterable<Value::_IChildren>::iterator
Value::Iterable<Value::_IChildren>::end() const noexcept
{
iterator ret{val, 0u};
if(val && (val.type()==TypeCode::Struct || val.type()==TypeCode::Union)) {
ret.pos = val.desc->miter.size();
}
return ret;
}
template<>
Value
Value::_Iterator<Value::_IChildren>::operator*() const noexcept
{
auto offset = val.desc->miter[pos].second;
Value ret;
if(val.type()==TypeCode::Struct) {
decltype (ret.store) store(val.store, val.store.get() + offset);
ret.store = std::move(store);
ret.desc = val.desc + offset;
} else if(val && val.type()==TypeCode::Union) {
auto pos_desc = &val.desc->members[val.desc->miter[pos].second];
if(val.store->as<Value>().desc==pos_desc) {
// pointing to selected Union field
ret = val.store->as<Value>();
} else {
std::shared_ptr<const FieldDesc> base(val.store, pos_desc);
ret = Value(base);
}
}
return ret;
}
static
void _next_marked(const Value& ref, size_t& pos, size_t& nextcheck)
{
if(pos < nextcheck)
return;
if(ref.type()==TypeCode::Struct) {
auto base_desc = Value::Helper::desc(ref);
while(pos < base_desc->mlookup.size()) {
auto desc = base_desc + 1u + pos;
auto S = Value::Helper::store_ptr(ref) + 1u + pos;
if(S->valid) {
auto D = desc + idx + 1u;
info.pos = idx;
info.nextcheck = idx + D->size();
nextcheck = pos + desc->size();
return;
}
++pos;
}
nextcheck = pos;
// end of iteration
info.pos = desc->mlookup.size();
info.nextcheck = info.pos+1;
} else if(ref.type()==TypeCode::Union) {
auto desc = Value::Helper::desc(ref);
} else if(desc->code==TypeCode::Union) {
assert(!info.depth); // the following assume
if(pos >= desc->miter.size())
return; // end of iteration
if(info.pos >= desc->miter.size())
return; // at end of iteration
const auto& val = Value::Helper::store_ptr(ref)->as<Value>();
size_t sel_idx = Value::Helper::desc(val) - desc->members.data();
size_t pos_idx = desc->miter[pos].second;
auto& val = store->as<Value>();
auto pos_desc = &desc->members[desc->miter[info.pos].second];
if(!val || pos_desc > val.desc) {
if(!val || pos_idx > sel_idx) {
// no field selected, or pos is after selection
// end of iteration
info.pos = desc->miter.size();
info.nextcheck = info.pos+1;
} else if(pos_desc < val.desc) {
pos = desc->miter.size();
} else if(pos_idx < sel_idx) {
// before selected
// jump forward to selection
for(auto i : range(info.pos, desc->miter.size())) {
if(val.desc==&desc->members[desc->miter[i].second]) {
info.pos = i;
info.nextcheck = i+1;
for(auto i : range(pos, desc->miter.size())) {
if(desc->miter[i].second == sel_idx) {
pos = i;
return;
}
}
@@ -950,42 +997,66 @@ void Value::_iter_advance(IterInfo& info) const
}
}
Value Value::_iter_deref(const IterInfo& info) const
template<>
Value::Iterable<Value::_IMarked>::iterator
Value::Iterable<Value::_IMarked>::begin() const noexcept
{
iterator ret{val, 0u};
_next_marked(ret.val, ret.pos, ret.nextcheck);
return ret;
}
template<>
Value::Iterable<Value::_IMarked>::iterator
Value::Iterable<Value::_IMarked>::end() const noexcept
{
iterator ret{val, 0u};
if(val && val.type()==TypeCode::Struct) {
ret.pos = val.desc->mlookup.size();
} else if(val && val.type()==TypeCode::Union) {
ret.pos = val.desc->miter.size();
}
ret.nextcheck = ret.pos;
return ret;
}
template<>
Value
Value::_Iterator<Value::_IMarked>::operator*() const noexcept
{
Value ret;
if(desc->code==TypeCode::Struct) {
auto idx = info.pos;
if(info.depth)
idx++; // indexing starts with FieldDesc after top
else
idx = desc->miter[idx].second;
if(val.type()==TypeCode::Struct) {
decltype (ret.store) store(val.store, val.store.get() + 1u + pos);
ret.store = std::move(store);
ret.desc = val.desc + 1u + pos;
assert(idx>0u);
assert(idx<desc->size());
decltype (store) store2(store, store.get()+idx);
ret.store = std::move(store2);
ret.desc = desc + idx;
} else if(val && val.type()==TypeCode::Union) {
auto pos_desc = &val.desc->members[val.desc->miter[pos].second];
} else if(desc->code==TypeCode::Union) {
auto pos_desc = &desc->members[desc->miter[info.pos].second];
if(desc->code==TypeCode::Union && store->as<Value>().desc==pos_desc) {
if(val.store->as<Value>().desc==pos_desc) {
// pointing to selected Union field
ret = store->as<Value>();
ret = val.store->as<Value>();
} else {
// array, or not selected union field.
// allocate temporary
std::shared_ptr<const FieldDesc> base(store, pos_desc);
std::shared_ptr<const FieldDesc> base(val.store, pos_desc);
ret = Value(base);
}
}
return ret;
}
template<>
Value::_Iterator<Value::_IMarked>&
Value::_Iterator<Value::_IMarked>::operator++() noexcept
{
pos++;
_next_marked(val, pos, nextcheck);
return *this;
}
namespace impl {
void FieldStorage::init(StoreType code)
+128 -81
View File
@@ -694,36 +694,25 @@ public:
//! only Struct, StructA, Union, UnionA return non-zero
size_t nmembers() const;
template<typename V>
class Iterable;
private:
struct IterInfo {
// when Marked==true, index of next potentially unmarked field.
// all [pos, nextcheck) are marked
size_t pos;
size_t nextcheck;
// true only iterates marked fields (Struct),
// or only the selected field (Union)
bool marked;
// false only iterates children (Struct only)
bool depth;
constexpr IterInfo() :pos(0u), nextcheck(0u), marked(false), depth(false) {}
constexpr IterInfo(size_t pos, bool marked, bool depth)
:pos(pos), nextcheck(pos), marked(marked), depth(depth)
{}
struct _IAll {};
struct _IChildren {};
struct _IMarked {
size_t nextcheck=0u;
};
template<typename V>
class Iter;
template<typename V>
friend class Iter;
void _iter_fl(IterInfo& info, bool first) const;
void _iter_advance(IterInfo& info) const;
Value _iter_deref(const IterInfo& info) const;
private:
template<typename T>
struct _Iterator;
template<typename T>
friend struct _Iterator;
public:
template<typename T>
struct Iterable;
template<typename T>
friend struct Iterable;
template<typename V>
class Iterable;
typedef Iterable<_IAll> IAll;
typedef Iterable<_IChildren> IChildren;
typedef Iterable<_IMarked> IMarked;
/** Depth-first iteration of all descendant fields
*
@@ -735,20 +724,13 @@ public:
* @endcode
*/
inline
Iterable<Value> iall();
IAll iall() const noexcept;
//! iteration of all child fields
inline
Iterable<Value> ichildren();
IChildren ichildren() const noexcept;
//! Depth-first iteration of all marked descendant fields
inline
Iterable<Value> imarked();
inline
Iterable<const Value> iall() const;
inline
Iterable<const Value> ichildren() const;
inline
Iterable<const Value> imarked() const;
IMarked imarked() const noexcept;
struct Fmt {
const Value* top = nullptr;
@@ -769,61 +751,126 @@ public:
inline Fmt format() const { return Fmt(this); }
};
template<typename V>
class Value::Iter : private Value::IterInfo {
Value ref;
constexpr Iter(const Value& ref, size_t pos, bool marked, bool depth)
:IterInfo(pos, marked, depth), ref(ref)
{}
template<typename T>
struct Value::_Iterator : private T
{
private:
Value val;
size_t pos = 0u;
friend class Value;
friend class Iterable<V>;
friend struct Iterable<T>;
constexpr _Iterator(const Value& val, size_t pos) : val(val), pos(pos) {}
public:
Iter() :ref(nullptr) {}
V operator*() const { return ref._iter_deref(*this); }
Iter& operator++() {
pos++;
if(pos >= nextcheck)
ref._iter_advance(*this);
return *this;
}
Iter operator++(int) {
Iter ret(*this);
_Iterator() = default;
Value operator*() const noexcept; // specialized per- _IterKind
_Iterator& operator++() noexcept; // specialized per- _IterKind
_Iterator operator++(int) noexcept {
_Iterator ret(*this);
++(*this);
return ret;
}
bool operator==(const Iter& o) const { return pos == o.pos; }
bool operator!=(const Iter& o) const { return !(o==*this); }
inline bool operator==(const _Iterator& o) const noexcept { return pos==o.pos; }
inline bool operator!=(const _Iterator& o) const noexcept { return pos!=o.pos; }
};
template<typename V>
class Value::Iterable {
Value owner;
bool marked = false;
bool depth = false;
template<typename T>
struct Value::Iterable
{
private:
Value val;
friend class Value;
public:
typedef Iter<V> iterator;
constexpr Iterable() = default;
constexpr Iterable(const Value& owner, bool marked, bool depth) :owner(owner), marked(marked), depth(depth) {}
iterator begin() const {
iterator ret{owner, 0u, marked, depth};
owner._iter_fl(ret, true);
return ret;
}
iterator end() const {
iterator ret{owner, 0u, marked, depth};
owner._iter_fl(ret, false);
return ret;
}
Iterable() = default;
explicit Iterable(const Value* val) :val(*val) {}
typedef _Iterator<T> iterator;
iterator begin() const noexcept; // specialized per- _IterKind
iterator end() const noexcept; // specialized per- _IterKind
};
Value::Iterable<Value> Value::iall() { return Iterable<Value>{*this, false, true}; }
Value::Iterable<Value> Value::ichildren() { return Iterable<Value>{*this, false, false}; }
Value::Iterable<Value> Value::imarked() { return Iterable<Value>{*this, true , true}; }
template<>
inline
Value::Iterable<Value::_IAll>::iterator
Value::Iterable<Value::_IAll>::begin() const noexcept {
return iterator(val, 0u); // always start pos==0
}
Value::Iterable<const Value> Value::iall() const { return Iterable<const Value>{*this, false, true}; }
Value::Iterable<const Value> Value::ichildren() const { return Iterable<const Value>{*this, false, false}; }
Value::Iterable<const Value> Value::imarked() const { return Iterable<const Value>{*this, true , true}; }
template<>
PVXS_API
Value::Iterable<Value::_IAll>::iterator
Value::Iterable<Value::_IAll>::end() const noexcept;
template<>
PVXS_API
Value
Value::_Iterator<Value::_IAll>::operator*() const noexcept;
template<>
inline
Value::_Iterator<Value::_IAll>&
Value::_Iterator<Value::_IAll>::operator++() noexcept {
pos++;
return *this;
}
template<>
inline
Value::Iterable<Value::_IChildren>::iterator
Value::Iterable<Value::_IChildren>::begin() const noexcept {
return iterator(val, 0u); // always start pos==0
}
template<>
PVXS_API
Value::Iterable<Value::_IChildren>::iterator
Value::Iterable<Value::_IChildren>::end() const noexcept;
template<>
PVXS_API
Value
Value::_Iterator<Value::_IChildren>::operator*() const noexcept;
template<>
inline
Value::_Iterator<Value::_IChildren>&
Value::_Iterator<Value::_IChildren>::operator++() noexcept {
pos++;
return *this;
}
template<>
PVXS_API
Value::Iterable<Value::_IMarked>::iterator
Value::Iterable<Value::_IMarked>::begin() const noexcept;
template<>
PVXS_API
Value::Iterable<Value::_IMarked>::iterator
Value::Iterable<Value::_IMarked>::end() const noexcept;
template<>
PVXS_API
Value
Value::_Iterator<Value::_IMarked>::operator*() const noexcept;
template<>
PVXS_API
Value::_Iterator<Value::_IMarked>&
Value::_Iterator<Value::_IMarked>::operator++() noexcept;
Value::Iterable<Value::_IAll>
Value::iall() const noexcept {
return Iterable<Value::_IAll>{this};
}
Value::Iterable<Value::_IChildren>
Value::ichildren() const noexcept {
return Iterable<Value::_IChildren>{this};
}
Value::Iterable<Value::_IMarked>
Value::imarked() const noexcept {
return Iterable<Value::_IMarked>{this};
}
PVXS_API
std::ostream& operator<<(std::ostream& strm, const Value::Fmt& fmt);
+3 -3
View File
@@ -149,14 +149,14 @@ void testIterStruct()
val.unmark();
val["alarm"].mark();
testMarked(4u)<<"mark sub-struct";
testMarked(4u)<<"mark alarm sub-struct";
val.unmark();
val["value"].mark(); // 1 field
val["alarm.status"].mark(); // 1 field
val["timeStamp"].mark(); // 4 fields (struct node and 3x leaves)
testMarked(6u)<<"mark sub-struct";
testMarked(6u)<<"mark multiple sub-struct";
}
void testIterUnion()
@@ -342,7 +342,7 @@ void testAssignSimilar()
MAIN(testdata)
{
testPlan(97);
testPlan(99);
testSetup();
testTraverse();
testAssign();