diff --git a/applications/test/sliceRange/Make/files b/applications/test/sliceRange/Make/files
new file mode 100644
index 0000000000..6d24718f23
--- /dev/null
+++ b/applications/test/sliceRange/Make/files
@@ -0,0 +1,3 @@
+Test-sliceRange.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-sliceRange
diff --git a/applications/test/sliceRange/Make/options b/applications/test/sliceRange/Make/options
new file mode 100644
index 0000000000..18e6fe47af
--- /dev/null
+++ b/applications/test/sliceRange/Make/options
@@ -0,0 +1,2 @@
+/* EXE_INC = */
+/* EXE_LIBS = */
diff --git a/applications/test/sliceRange/Test-sliceRange.C b/applications/test/sliceRange/Test-sliceRange.C
new file mode 100644
index 0000000000..477283ebb7
--- /dev/null
+++ b/applications/test/sliceRange/Test-sliceRange.C
@@ -0,0 +1,136 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / 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 .
+
+Description
+ Test slice range
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "labelList.H"
+#include "FixedList.H"
+#include "sliceRange.H"
+
+using namespace Foam;
+
+
+typedef FixedList 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;
+}
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index b3c9ecfdcc..0e7ae03ba7 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -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
diff --git a/src/OpenFOAM/primitives/ranges/sliceRange/sliceRange.C b/src/OpenFOAM/primitives/ranges/sliceRange/sliceRange.C
new file mode 100644
index 0000000000..0a39749b26
--- /dev/null
+++ b/src/OpenFOAM/primitives/ranges/sliceRange/sliceRange.C
@@ -0,0 +1,78 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / 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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "sliceRange.H"
+#include "FixedList.H"
+#include "List.H"
+#include "token.H"
+#include
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::sliceRange::sliceRange(const FixedList& 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::sliceRange::labels() const
+{
+ List 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;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/ranges/sliceRange/sliceRange.H b/src/OpenFOAM/primitives/ranges/sliceRange/sliceRange.H
new file mode 100644
index 0000000000..f94faccd06
--- /dev/null
+++ b/src/OpenFOAM/primitives/ranges/sliceRange/sliceRange.H
@@ -0,0 +1,345 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / 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 .
+
+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
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward Declarations
+class Ostream;
+template class List;
+template 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& 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 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
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/ranges/sliceRange/sliceRangeI.H b/src/OpenFOAM/primitives/ranges/sliceRange/sliceRangeI.H
new file mode 100644
index 0000000000..e5d8780c5b
--- /dev/null
+++ b/src/OpenFOAM/primitives/ranges/sliceRange/sliceRangeI.H
@@ -0,0 +1,208 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / 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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include
+
+// * * * * * * * * * * * * * * * * 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_
+ )
+{}
+
+
+inline void Foam::sliceRange::indexer::next() noexcept
+{
+ value_ += stride_;
+}
+
+
+inline void Foam::sliceRange::indexer::next(const label n) noexcept
+{
+ value_ += (n * stride_);
+}
+
+
+inline bool Foam::sliceRange::indexer::equals
+(
+ const indexer& other
+) const noexcept
+{
+ return (value_ == other.value_);
+}
+
+
+inline Foam::label Foam::sliceRange::indexer::operator*() const noexcept
+{
+ return value_;
+}
+
+
+inline Foam::label Foam::sliceRange::indexer::operator()()
+{
+ const label old(value_);
+ next();
+ return old;
+}
+
+
+inline Foam::sliceRange::const_iterator::const_iterator
+(
+ const sliceRange* range,
+ const label i
+)
+:
+ indexer(range, i)
+{}
+
+
+inline Foam::sliceRange::const_iterator&
+Foam::sliceRange::const_iterator::operator++() noexcept
+{
+ next();
+ return *this;
+}
+
+
+inline Foam::sliceRange::const_iterator&
+Foam::sliceRange::const_iterator::operator+=(const label n) noexcept
+{
+ next(n);
+ return *this;
+}
+
+
+inline Foam::sliceRange::const_iterator&
+Foam::sliceRange::const_iterator::operator--() noexcept
+{
+ next(-1);
+ return *this;
+}
+
+
+inline Foam::sliceRange::const_iterator&
+Foam::sliceRange::const_iterator::operator-=(const label n) noexcept
+{
+ next(-n);
+ return *this;
+}
+
+
+inline bool Foam::sliceRange::const_iterator::operator==
+(
+ const const_iterator& iter
+) const noexcept
+{
+ return equals(iter);
+}
+
+
+inline bool Foam::sliceRange::const_iterator::operator!=
+(
+ const const_iterator& iter
+) const noexcept
+{
+ return !equals(iter);
+}
+
+
+inline Foam::sliceRange::const_iterator Foam::sliceRange::begin() const
+{
+ return const_iterator(this, 0);
+}
+
+
+inline Foam::sliceRange::const_iterator Foam::sliceRange::cbegin() const
+{
+ return const_iterator(this, 0);
+}
+
+
+inline const Foam::sliceRange::const_iterator Foam::sliceRange::end() const
+{
+ return const_iterator(this, -1);
+}
+
+
+inline const Foam::sliceRange::const_iterator Foam::sliceRange::cend() const
+{
+ return const_iterator(this, -1);
+}
+
+
+inline Foam::sliceRange::indexer Foam::sliceRange::generator() const
+{
+ return indexer(this, 0);
+}
+
+
+inline Foam::sliceRange::const_iterator
+Foam::sliceRange::at(const label i) const
+{
+ return const_iterator(this, i);
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
+
+inline Foam::label Foam::sliceRange::operator[](const label i) const noexcept
+{
+ return start_ + stride_ * i;
+}
+
+
+// ************************************************************************* //