Commit c25a40dd authored by Mark Olesen's avatar Mark Olesen

ENH: new sliceRange class

- this is somewhat like labelRange, but with a stride.
  Can be used to define slices (of lists, fields, ..) or as a range specifier
  for a for-loop. For example,

      for (label i : sliceRange(0, 10, 3))
      {
          ...
      }
parent 918e1f40
Test-sliceRange.C
EXE = $(FOAM_USER_APPBIN)/Test-sliceRange
/* EXE_INC = */
/* EXE_LIBS = */
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Test slice range
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "labelList.H"
#include "FixedList.H"
#include "sliceRange.H"
using namespace Foam;
typedef FixedList<label, 3> sliceCoeffs;
void printInfo(const sliceCoeffs& coeffs)
{
sliceRange range(coeffs);
Info<< nl
<< "coeffs: " << coeffs << nl
<< "range: " << range << nl
<< "first: " << range.first() << nl
<< "*begin " << *range.begin() << nl
<< "last: " << range.last() << nl
<< "*end " << *range.end() << nl
<< "values: " << flatOutput(range.labels()) << nl;
Info<< "for :";
for (const label val : range)
{
Info<< ' ' << val;
}
Info<< nl;
if (range.empty())
{
Info<< "empty"<< nl;
return;
}
Info<< "mid-point [" << (range.size()/2) << "] = "
<< range[range.size()/2] << nl;
const auto endIter = range.cend();
for (const label i : {-1, (range.size()/2), range.size()})
{
const auto iter = range.at(i);
Info<< "at(" << i << ") = " << *iter;
if (iter == endIter)
{
Info<< " (out-of-range)";
}
Info<< nl;
}
// Copy construct
sliceRange range2(range);
// Copy assign
range2 = range;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
argList::noBanner();
argList::noParallel();
argList::noFunctionObjects();
argList args(argc, argv, false, true);
for
(
sliceCoeffs coeffs :
{
sliceCoeffs{25, 8, 2},
sliceCoeffs{15, 5, 3},
sliceCoeffs{15, -5, 2},
}
)
{
printInfo(coeffs);
}
// Generator
{
sliceRange range(25, 8, 3);
Info<< "Generator for " << range << nl;
auto gen = range.generator();
for (label i=0; i < 10; ++i)
{
Info<< " " << gen() << nl;
}
}
Info<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //
......@@ -147,6 +147,7 @@ $(ranges)/labelRange/labelRange.C
$(ranges)/labelRange/labelRanges.C
$(ranges)/scalarRange/scalarRange.C
$(ranges)/scalarRange/scalarRanges.C
$(ranges)/sliceRange/sliceRange.C
$(ranges)/tableBounds/tableBounds.C
spatialVectorAlgebra = primitives/spatialVectorAlgebra
......
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sliceRange.H"
#include "FixedList.H"
#include "List.H"
#include "token.H"
#include <algorithm>
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::sliceRange::sliceRange(const FixedList<label,3>& coeffs)
:
start_(coeffs[0]),
size_(std::max(0,coeffs[1])), // No negative size
stride_(std::max(0,coeffs[2])) // No negative stride
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::List<Foam::label> Foam::sliceRange::labels() const
{
List<label> result(size_);
if (stride_)
{
std::copy(cbegin(), cend(), result.begin());
// Or even this
// std::generate(result.begin(), result.end(), generator());
}
else
{
std::fill(result.begin(), result.end(), start_);
}
return result;
}
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const sliceRange& range)
{
os << token::BEGIN_LIST
<< range.start() << token::SPACE
<< range.size() << token::SPACE
<< range.stride() << token::END_LIST;
os.check(FUNCTION_NAME);
return os;
}
// ************************************************************************* //
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::sliceRange
Description
A set of labels defined by a start, a length and a stride.
SourceFiles
sliceRange.C
sliceRangeI.H
\*---------------------------------------------------------------------------*/
#ifndef sliceRange_H
#define sliceRange_H
#include "label.H"
#include <iterator>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class Ostream;
template<class T> class List;
template<class T, unsigned N> class FixedList;
/*---------------------------------------------------------------------------*\
Class sliceRange Declaration
\*---------------------------------------------------------------------------*/
class sliceRange
{
protected:
// Protected Data
//- The start point for the interval
label start_;
//- The length of the interval
label size_;
//- The stride within the interval
label stride_;
public:
// STL type definitions
//- Type of values the range contains
typedef label value_type;
//- The type that can represent the size of the range
typedef label size_type;
//- Forward iterator with const access
class const_iterator;
// Constructors
//- Default copy construct
sliceRange(const sliceRange&) = default;
//- Default move construct
sliceRange(sliceRange&&) = default;
//- An empty slice (0,0,0)
inline constexpr sliceRange() noexcept;
//- Construct slice from start/size/stride,
//- enforcing non-negative size and stride.
inline sliceRange(label start, label size, label stride) noexcept;
//- Construct slice from start/size/stride coefficients,
//- enforcing non-negative size and stride.
explicit sliceRange(const FixedList<label,3>& coeffs);
// Member Functions
//- Is the range empty?
bool empty() const noexcept
{
return !size_;
}
//- Is the range non-empty?
bool valid() const noexcept
{
return size_;
}
//- The (inclusive) lower value of the range
constexpr label start() const noexcept
{
return start_;
}
//- The size of the range
constexpr label size() const noexcept
{
return size_;
}
//- The stride for the range
constexpr label stride() const noexcept
{
return stride_;
}
//- The (inclusive) lower value of the range - same as start()
constexpr label first() const noexcept
{
return start_;
}
//- The (inclusive) upper value of the range
label last() const noexcept
{
return start_ + (size_-1) * stride_;
}
//- Return the slice as a list of labels
List<label> labels() const;
// Member Operators
//- Default copy assignment
sliceRange& operator=(const sliceRange&) = default;
//- Default move assignment
sliceRange& operator=(sliceRange&&) = default;
//- Return element in the range, without bounds checking
inline label operator[](const label i) const noexcept;
// Iterators
//- A value indexer, for iteration or generation
class indexer
{
//- The stride when indexing
const label stride_;
//- The global value
label value_;
public:
// Constructors
//- Construct from range at given local index.
// An out-of-range index (eg, negative) creates an 'end' iterator
inline indexer(const sliceRange* range, const label i=0);
// Member Functions
//- Forward increment, no checking
inline void next() noexcept;
//- Forward increment, no checking
inline void next(const label n) noexcept;
//- Test for equality of values, not stride
inline bool equals(const indexer& other) const noexcept;
public:
// Member Operators
//- Return the value
inline label operator*() const noexcept;
//- Apply a postfix increment and return the current value.
// This operator definition is required for a generator -
// see std::generate()
inline label operator()();
};
//- Forward iterator with const access
class const_iterator
:
protected indexer,
public std::iterator
<
std::input_iterator_tag,
label,
label,
const label*,
const label&
>
{
public:
// Constructors
//- Construct from range at given local index.
// An out-of-range index (eg, negative) creates an 'end' iterator
inline const_iterator(const sliceRange* range, const label i=0);
// Member Operators
//- Return the (global) value
using indexer::operator*;
//- Prefix increment, no checking
inline const_iterator& operator++() noexcept;
//- Arbitrary increment, no checking
inline const_iterator& operator+=(const label n) noexcept;
//- Prefix decrement, no checking
inline const_iterator& operator--() noexcept;
//- Arbitrary decrement, no checking
inline const_iterator& operator-=(const label n) noexcept;
//- Test for equality of values, not stride
inline bool operator==(const const_iterator& iter) const noexcept;
//- Test for inequality of values, not stride
inline bool operator!=(const const_iterator& iter) const noexcept;
};
//- A const_iterator set to the beginning of the range
// The value returned is guaranteed to be the same as start()
inline const_iterator begin() const;
//- A const_iterator set to the beginning of the range
// The value returned is guaranteed to be the same as start()
inline const_iterator cbegin() const;
//- A const_iterator set to 1 beyond the end of the range.
// The value returned is the same as after()
inline const const_iterator cend() const;
//- A const_iterator set to 1 beyond the end of the range.
// The value returned is the same as after()
inline const const_iterator end() const;
//- Return a forward values generator
inline indexer generator() const;
//- Return const_iterator to a position within the range,
//- with bounds checking.
// \return iterator at the requested position, or end() for
// out of bounds
inline const_iterator at(const label i) const;
};
// IOstream Operators
//- Write sliceRange to Ostream as (start size stride) tuple
Ostream& operator<<(Ostream& os, const sliceRange& range);
// Global Operators
inline bool operator==(const sliceRange& a, const sliceRange& b) noexcept
{
return
(
a.first() == b.first()
&& a.size() == b.size()
&& a.stride() == b.stride()
);
}
inline bool operator!=(const sliceRange& a, const sliceRange& b) noexcept
{
return !(a == b);
}
//- Comparison function for sorting, compares the start.
// If the start values are equal, also compares the size.
// If the sizes are equal, also compares the stride.
inline bool operator<(const sliceRange& a, const sliceRange& b) noexcept
{
return
(
a.first() < b.first()
||
(
!(b.first() < a.first())
&&
(
a.size() < b.size()
||
(
!(b.size() < a.size())
&& a.stride() < b.stride()
)
)
)
);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "sliceRangeI.H"
#endif
// ************************************************************************* //
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include <algorithm>
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline constexpr Foam::sliceRange::sliceRange() noexcept
:
start_(0),
size_(0),
stride_(0)
{}
inline Foam::sliceRange::sliceRange
(
const label start,
const label size,
const label stride
) noexcept
:
start_(start),
size_(std::max(0,size)), // No negative size
stride_(std::max(0,stride)) // No negative stride
{}
// * * * * * * * * * * * * * * * * Iterators * * * * * * * * * * * * * * * * //
inline Foam::sliceRange::indexer::indexer
(
const sliceRange* range,
const label i
)
:
stride_(range->stride()),
value_
(
range->start()
+ ((i < 0 || i > range->size()) ? range->size() : i) * stride_