You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
8.1 KiB
C++
235 lines
8.1 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkCollectionRange.h
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
|
|
#ifndef vtkCollectionRange_h
|
|
#define vtkCollectionRange_h
|
|
|
|
#ifndef __VTK_WRAP__
|
|
|
|
#include "vtkCollection.h"
|
|
#include "vtkMeta.h"
|
|
#include "vtkRange.h"
|
|
#include "vtkSmartPointer.h"
|
|
|
|
#include <cassert>
|
|
|
|
namespace vtk
|
|
{
|
|
namespace detail
|
|
{
|
|
|
|
template <typename CollectionType>
|
|
struct CollectionRange;
|
|
template <typename CollectionType>
|
|
struct CollectionIterator;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Detect vtkCollection types
|
|
template <typename T>
|
|
struct IsCollection : std::is_base_of<vtkCollection, T>
|
|
{
|
|
};
|
|
|
|
template <typename CollectionType, typename T = CollectionType>
|
|
using EnableIfIsCollection = typename std::enable_if<IsCollection<CollectionType>::value, T>::type;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Detect the type of items held by the collection by checking the return type
|
|
// of GetNextItem(), or GetNextItemAsObject() as a fallback.
|
|
template <typename CollectionType>
|
|
struct GetCollectionItemType
|
|
{
|
|
static_assert(IsCollection<CollectionType>::value, "Invalid vtkCollection subclass.");
|
|
|
|
private:
|
|
// The GetType methods are only used in a decltype context and are left
|
|
// unimplemented as we only care about their signatures. They are used to
|
|
// determine the type of object held by the collection.
|
|
//
|
|
// By passing literal 0 as the argument, the overload taking `int` is
|
|
// preferred and returns the same type as CollectionType::GetNextItem, which
|
|
// is usually the exact type held by the collection (e.g.
|
|
// vtkRendererCollection::GetNextItem returns vtkRenderer*).
|
|
//
|
|
// If the collection class does not define GetNextItem, SFINAE removes the
|
|
// preferred `int` overload, and the `...` overload is used instead. This
|
|
// method returns the same type as vtkCollection::GetNextItemAsObject, which
|
|
// is vtkObject*. This lets us define a more derived collection item type
|
|
// when possible, while falling back to the general vtkObject if a more
|
|
// refined type is not known.
|
|
|
|
// not implemented
|
|
template <typename T>
|
|
static auto GetType(...) -> decltype(std::declval<T>().GetNextItemAsObject());
|
|
|
|
// not implemented
|
|
template <typename T>
|
|
static auto GetType(int) -> decltype(std::declval<T>().GetNextItem());
|
|
|
|
using PointerType = decltype(GetType<CollectionType>(0));
|
|
|
|
public:
|
|
// Just use std::remove pointer, vtk::detail::StripPointer is overkill.
|
|
using Type = typename std::remove_pointer<PointerType>::type;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Collection iterator. Reference, value, and pointer types are all ItemType
|
|
// pointers, since:
|
|
// a) values: ItemType* instead of ItemType because vtkObjects can't be
|
|
// copied/assigned.
|
|
// b) references: No good usecase to change the pointers held by the collection
|
|
// by returning ItemType*&, nor would returning ItemType& be useful, since
|
|
// it'd have to be dereferenced anyway to pass it anywhere, and vtkObjects
|
|
// are conventionally held by address.
|
|
// c) pointers: Returning ItemType** from operator-> would be useless.
|
|
//
|
|
// There are no const_reference, etc, since VTK is not const correct and marking
|
|
// vtkObjects consts makes them unusable.
|
|
template <typename CollectionType>
|
|
struct CollectionIterator
|
|
: public std::iterator<std::forward_iterator_tag,
|
|
typename GetCollectionItemType<CollectionType>::Type*, int,
|
|
typename GetCollectionItemType<CollectionType>::Type*,
|
|
typename GetCollectionItemType<CollectionType>::Type*>
|
|
{
|
|
static_assert(IsCollection<CollectionType>::value, "Invalid vtkCollection subclass.");
|
|
|
|
private:
|
|
using ItemType = typename GetCollectionItemType<CollectionType>::Type;
|
|
using Superclass = std::iterator<std::forward_iterator_tag, ItemType*, int, ItemType*, ItemType*>;
|
|
|
|
public:
|
|
using iterator_category = typename Superclass::iterator_category;
|
|
using value_type = typename Superclass::value_type;
|
|
using difference_type = typename Superclass::difference_type;
|
|
using pointer = typename Superclass::pointer;
|
|
using reference = typename Superclass::reference;
|
|
|
|
CollectionIterator() noexcept : Element(nullptr) {}
|
|
|
|
CollectionIterator(const CollectionIterator& o) noexcept = default;
|
|
CollectionIterator& operator=(const CollectionIterator& o) noexcept = default;
|
|
|
|
CollectionIterator& operator++() noexcept // prefix
|
|
{
|
|
this->Increment();
|
|
return *this;
|
|
}
|
|
|
|
CollectionIterator operator++(int) noexcept // postfix
|
|
{
|
|
auto elem = this->Element;
|
|
this->Increment();
|
|
return CollectionIterator{ elem };
|
|
}
|
|
|
|
reference operator*() const noexcept { return this->GetItem(); }
|
|
|
|
pointer operator->() const noexcept { return this->GetItem(); }
|
|
|
|
friend bool operator==(const CollectionIterator& lhs, const CollectionIterator& rhs) noexcept
|
|
{
|
|
return lhs.Element == rhs.Element;
|
|
}
|
|
|
|
friend bool operator!=(const CollectionIterator& lhs, const CollectionIterator& rhs) noexcept
|
|
{
|
|
return lhs.Element != rhs.Element;
|
|
}
|
|
|
|
friend void swap(CollectionIterator& lhs, CollectionIterator& rhs) noexcept
|
|
{
|
|
using std::swap;
|
|
swap(lhs.Element, rhs.Element);
|
|
}
|
|
|
|
friend struct CollectionRange<CollectionType>;
|
|
|
|
protected:
|
|
CollectionIterator(vtkCollectionElement* element) noexcept : Element(element) {}
|
|
|
|
private:
|
|
void Increment() noexcept
|
|
{ // incrementing an invalid iterator is UB, no need to check for non-null.
|
|
this->Element = this->Element->Next;
|
|
}
|
|
|
|
ItemType* GetItem() const noexcept { return static_cast<ItemType*>(this->Element->Item); }
|
|
|
|
vtkCollectionElement* Element;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Collection range proxy.
|
|
// The const_iterators/references are the same as the non-const versions, since
|
|
// vtkObjects marked const are unusable.
|
|
template <typename CollectionType>
|
|
struct CollectionRange
|
|
{
|
|
static_assert(IsCollection<CollectionType>::value, "Invalid vtkCollection subclass.");
|
|
|
|
using ItemType = typename GetCollectionItemType<CollectionType>::Type;
|
|
|
|
// NOTE: The const items are the same as the mutable ones, since const
|
|
// vtkObjects are generally unusable.
|
|
using size_type = int; // int is used by the vtkCollection API.
|
|
using iterator = CollectionIterator<CollectionType>;
|
|
using const_iterator = CollectionIterator<CollectionType>;
|
|
using reference = ItemType*;
|
|
using const_reference = ItemType*;
|
|
using value_type = ItemType*;
|
|
|
|
CollectionRange(CollectionType* coll) noexcept : Collection(coll) { assert(this->Collection); }
|
|
|
|
CollectionType* GetCollection() const noexcept { return this->Collection; }
|
|
|
|
size_type size() const noexcept { return this->Collection->GetNumberOfItems(); }
|
|
|
|
iterator begin() const
|
|
{
|
|
vtkCollectionSimpleIterator cookie;
|
|
this->Collection->InitTraversal(cookie);
|
|
// The cookie is a linked list node pointer, vtkCollectionElement:
|
|
return iterator{ static_cast<vtkCollectionElement*>(cookie) };
|
|
}
|
|
|
|
iterator end() const { return iterator{ nullptr }; }
|
|
|
|
// Note: These return mutable objects because const vtkObject are unusable.
|
|
const_iterator cbegin() const
|
|
{
|
|
vtkCollectionSimpleIterator cookie;
|
|
this->Collection->InitTraversal(cookie);
|
|
// The cookie is a linked list node pointer, vtkCollectionElement:
|
|
return const_iterator{ static_cast<vtkCollectionElement*>(cookie) };
|
|
}
|
|
|
|
// Note: These return mutable objects because const vtkObjects are unusable.
|
|
const_iterator cend() const { return const_iterator{ nullptr }; }
|
|
|
|
private:
|
|
vtkSmartPointer<CollectionType> Collection;
|
|
};
|
|
|
|
}
|
|
} // end namespace vtk::detail
|
|
|
|
#endif // __VTK_WRAP__
|
|
|
|
#endif // vtkCollectionRange_h
|
|
|
|
// VTK-HeaderTest-Exclude: vtkCollectionRange.h
|