View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0004231 | NoesisGUI | C++ SDK | public | 2025-06-06 13:12 | 2026-07-31 16:56 |
| Reporter | Logris | Assigned To | jsantos | ||
| Priority | normal | Severity | feature | ||
| Status | assigned | Resolution | open | ||
| Product Version | 3.2 | ||||
| Target Version | 3.2.14 | ||||
| Summary | 0004231: Implementation of a range-based loop for ObservableCollection | ||||
| Description | |||||
| Platform | Any | ||||
|
as an idea, to use a range-like approach for working with a collection for(auto item : Noesis::Cast<Component>(Noesis::Skip<2>(Items)) { |
|
|
ObservableCollectionIterator.h (6,937 bytes)
#pragma once
#include <NsGui/ObservableCollection.h>
#include <NsCore/Ptr.h>
namespace Noesis
{
template<typename T>
class ObservableCollectionIterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = T*;
using difference_type = std::ptrdiff_t;
using pointer = T**;
using reference = T*&;
ObservableCollectionIterator(ObservableCollection<T>* collection, uint32_t index)
: mCollection(collection), mIndex(index)
{
}
T* operator*() const { return mCollection->Get(mIndex); }
ObservableCollectionIterator& operator++() { ++mIndex; return *this; }
bool operator==(const ObservableCollectionIterator& other) const
{
return mIndex == other.mIndex;
}
bool operator!=(const ObservableCollectionIterator& other) const
{
return !(*this == other);
}
private:
ObservableCollection<T>* mCollection;
uint32_t mIndex;
};
template<typename T>
ObservableCollectionIterator<T> begin(ObservableCollection<T>* collection)
{
return { collection, 0 };
}
template<typename T>
ObservableCollectionIterator<T> begin(const ObservableCollection<T>* collection)
{
return { collection, 0 };
}
template<typename T>
ObservableCollectionIterator<T> begin(Ptr<ObservableCollection<T>>& collection)
{
return { collection.GetPtr(), 0 };
}
template<typename T>
ObservableCollectionIterator<T> begin(const Ptr<ObservableCollection<T>>& collection)
{
return { collection.GetPtr(), 0 };
}
template<typename T>
ObservableCollectionIterator<T> end(ObservableCollection<T>* collection)
{
return { collection, static_cast<uint32_t>(collection->Count()) };
}
template<typename T>
ObservableCollectionIterator<T> end(const ObservableCollection<T>* collection)
{
return { collection, static_cast<uint32_t>(collection->Count()) };
}
template<typename T>
ObservableCollectionIterator<T> end(Ptr<ObservableCollection<T>>& collection)
{
return { collection.GetPtr(), static_cast<uint32_t>(collection->Count())};
}
template<typename T>
ObservableCollectionIterator<T> end(const Ptr<ObservableCollection<T>>& collection)
{
return { collection.GetPtr(), static_cast<uint32_t>(collection->Count()) };
}
}
namespace Noesis
{
//Adapters for begin/end
namespace Detail {
using std::begin; using std::end;
template<class Range>
auto Begin(Range&& r) -> decltype(begin(std::forward<Range>(r))) {
return begin(std::forward<Range>(r));
}
template<class Range>
auto End(Range&& r) -> decltype(end(std::forward<Range>(r))) {
return end(std::forward<Range>(r));
}
// Skip with offset
template<class Range>
auto Begin(Range&& r, std::size_t offset) -> decltype(begin(std::forward<Range>(r))) {
auto b = begin(std::forward<Range>(r));
auto e = end(std::forward<Range>(r));
while (offset-- > 0 && b != e) ++b;
return b;
}
// Skip specializations for ObservableCollection
template<typename T>
ObservableCollectionIterator<T> Begin(ObservableCollection<T>* collection, std::size_t offset) {
if (!collection) return { nullptr, 0 };
const uint32_t count = collection->Count();
const uint32_t startIndex = (offset < count) ? static_cast<uint32_t>(offset) : count;
return { collection, startIndex };
}
template<typename T>
ObservableCollectionIterator<T> Begin(const ObservableCollection<T>* collection, std::size_t offset) {
return Begin(const_cast<ObservableCollection<T>*>(collection), offset);
}
template<typename T>
ObservableCollectionIterator<T> Begin(Ptr<ObservableCollection<T>>& collection, std::size_t offset) {
return Begin(collection.GetPtr(), offset);
}
template<typename T>
ObservableCollectionIterator<T> Begin(const Ptr<ObservableCollection<T>>& collection, std::size_t offset) {
return Begin(collection.GetPtr(), offset);
}
template<typename T>
ObservableCollectionIterator<T> Begin(ObservableCollection<T>& collection, std::size_t offset) {
return Begin(&collection, offset);
}
template<typename T>
ObservableCollectionIterator<T> Begin(const ObservableCollection<T>& collection, std::size_t offset) {
return Begin(const_cast<ObservableCollection<T>*>(&collection), offset);
}
}
template<typename TDerived, typename TRange>
class CastRange
{
using BaseIterator = decltype(Detail::Begin(std::declval<TRange>()));
using BaseType = std::remove_pointer_t<decltype(*std::declval<BaseIterator>())>;
static_assert(std::is_pointer_v<decltype(*std::declval<BaseIterator>())>,
"CastRange can only be used with ranges of pointers");
static_assert(IsDerived<TDerived, BaseType>::Result,
"Derived must inherit from range element type");
public:
explicit CastRange(TRange&& range)
: mRange(std::forward<TRange>(range)) {
}
class Iterator
{
public:
using BaseIterator = decltype(Detail::Begin(std::declval<TRange>()));
Iterator(BaseIterator it) : mIt(it) {
}
TDerived* operator*() const {
return static_cast<TDerived*>(*mIt);
}
Iterator& operator++() {
++mIt;
return *this;
}
bool operator==(const Iterator& other) const {
return mIt == other.mIt;
}
bool operator!=(const Iterator& other) const {
return mIt != other.mIt;
}
private:
BaseIterator mIt;
};
Iterator begin() const {
return Iterator(Detail::Begin(mRange));
}
Iterator end() const {
return Iterator(Detail::End(mRange));
}
private:
TRange mRange;
};
template<typename TDerived, typename TRange>
auto Cast(TRange&& range)
{
return CastRange<TDerived, TRange>(std::forward<TRange>(range));
}
// // Cast functions for ObservableCollection
//
// template<typename TDerived, typename T>
// auto Cast(ObservableCollection<T>* collection)
// {
// return CastRange<TDerived, T>(collection);
// }
//
// template<typename TDerived, typename T>
// auto Cast(Ptr<ObservableCollection<T>>& collection)
// {
// return CastRange<TDerived, T>(collection);
// }
//
// template<typename TDerived, typename T>
// auto Cast(const Ptr<ObservableCollection<T>>& collection)
// {
// return CastRange<TDerived, T>(collection);
// }
}
namespace Noesis
{
template<std::size_t Offset, class TRange>
class SkipRange
{
using Range = std::decay_t<TRange>;
public:
explicit SkipRange(Range range) : mRange(std::move(range)) {}
auto begin() const {
return Detail::Begin(mRange, Offset);
}
auto end() const {
return Detail::End(mRange);
}
private:
Range mRange;
};
template<std::size_t Offset, class Range>
auto Skip(Range&& range) {
using R = std::decay_t<Range>;
return SkipRange<Offset, R>(std::forward<Range>(range));
}
} |
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2025-06-06 13:12 | Logris | New Issue | |
| 2025-06-06 13:27 | jsantos | Assigned To | => jsantos |
| 2025-06-06 13:27 | jsantos | Status | new => assigned |
| 2025-06-06 13:27 | jsantos | Target Version | => 3.2.9 |
| 2025-08-16 16:35 | Logris | Note Added: 0010985 | |
| 2025-08-16 16:35 | Logris | Note Added: 0010986 | |
| 2025-08-16 16:37 | Logris | Note Edited: 0010986 | |
| 2025-08-28 12:30 | Logris | Note Edited: 0010985 | |
| 2025-08-28 12:34 | Logris | Note Edited: 0010986 | |
| 2025-08-28 12:37 | Logris | Note Edited: 0010985 | |
| 2025-08-28 12:37 | Logris | Note Added: 0011020 | |
| 2025-08-28 12:37 | Logris | File Added: ObservableCollectionIterator.h | |
| 2025-10-02 00:48 | jsantos | Target Version | 3.2.9 => 3.2.10 |
| 2025-10-20 18:25 | jsantos | Target Version | 3.2.10 => 3.2.11 |
| 2026-01-20 19:32 | jsantos | Target Version | 3.2.11 => 3.2.12 |
| 2026-03-04 00:39 | jsantos | Target Version | 3.2.12 => 3.2.13 |
| 2026-04-27 12:16 | jsantos | Target Version | 3.2.13 => 3.2.14 |
| 2026-07-31 16:56 | jsantos | Relationship added | related to 0005155 |