Value iteration take 3
This commit is contained in:
+153
-82
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user