ENH: support List sub-slice searching, use std::find()

- support UList shallowCopy with pointer/size
  (eg, for slicing into or from span)

ENH: add SubList::reset() functionality

- allows modification of a SubList after construction.
  Previously a SubList had an immutable location after construction
  and there was no way to shift or change its location.

BUG: missed special handling for DynamicList<char>::readList (fixes #2974)

- equivalent to List<char>::readList, in which the stream is
  temporarily toggled from ASCII to BINARY when reading in a List of
  char data.
  This specialization was missed when DynamicList<T>::readList() was
  fully implemented.
This commit is contained in:
Mark Olesen 2023-08-30 14:54:36 +02:00
parent aa1b6d9cbd
commit 0250a1b0bb
19 changed files with 391 additions and 95 deletions

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -37,6 +37,7 @@ Description
#include "scalarField.H"
#include "SubField.H"
#include "labelRange.H"
#include "ListOps.H"
#include <numeric>
using namespace Foam;
@ -57,26 +58,26 @@ int main(int argc, char *argv[])
argList::noFunctionObjects();
{
List<scalar> ident(25);
List<label> ident(25);
std::iota(ident.begin(), ident.end(), 0);
print(ident);
SubList<scalar>(ident, 10) = -10;
SubList<label>(ident, 10) = -10;
print(ident);
SubField<scalar>(ident, 10) = 10;
SubField<label>(ident, 10) = 10;
print(ident);
SubField<scalar>(ident, 10) += 10;
SubField<label>(ident, 10) += 10;
print(ident);
SubField<scalar>{ident, 10, 10} *= 5;
SubField<label>{ident, 10, 10} *= 5;
print(ident);
// NOTE: Need {} instead of ()
// SubList<scalar>(ident) = 100;
// SubList<label>(ident) = 100;
// GCC
// error: conflicting declaration 'Foam::SubList<double> ident'
@ -85,7 +86,30 @@ int main(int argc, char *argv[])
// warning: parentheses were disambiguated as redundant parentheses
// around declaration of variable named 'ident' [-Wvexing-parse]
SubList<scalar>{ident} = 100;
SubList<label>{ident} = 100;
print(ident);
SubList<label> sub(ident);
sub = 1;
print(sub);
sub.reset(ident, labelRange(4, 5)) = 5;
print(sub);
print(ident);
sub.reset(ident, labelRange(14, 5)) = 15;
print(sub);
print(ident);
// Cryptic, probably not a great idea to write this
sub.reset(ident, {20, 3}) = -1;
print(sub);
print(ident);
// This is also possible since we hold a concrete pointer/size
// and not an intermediate
ListOps::identity(sub.reset(ident, 8, 8));
print(sub);
print(ident);
}

View File

@ -108,6 +108,8 @@ const Foam::SubList<T> Foam::CircularBuffer<T>::array_two() const
template<class T>
Foam::label Foam::CircularBuffer<T>::find(const T& val, label pos) const
{
if (pos < 0) return -1; // no-op
label i = -1;
const auto list1 = this->array_one();

View File

@ -282,18 +282,21 @@ public:
// Search
//- True if the value is contained in the list.
inline bool contains(const T& val) const;
//- Is the value contained in the list?
// \param val The value to search for
// \param pos The first position to examine (no-op if -ve)
// \return true if found.
inline bool contains(const T& val, label pos) const;
//- Find index of the first occurrence of the value.
// Any occurrences before the start pos are ignored.
// Linear search.
// \return position in list or -1 if not found.
label find(const T& val, label pos = 0) const;
//- Is the value contained in the list?
// Linear search from start pos until the end of the list.
// Any occurrences before the start pos are ignored.
// \return true if found.
inline bool contains(const T& val, label pos = 0) const;
// Stack-like Operations

View File

@ -255,6 +255,13 @@ inline void Foam::CircularBuffer<T>::reserve_nocopy(const label len)
}
template<class T>
bool Foam::CircularBuffer<T>::contains(const T& val) const
{
return (this->array_one().contains(val) || this->array_two().contains(val));
}
template<class T>
inline bool Foam::CircularBuffer<T>::contains(const T& val, label pos) const
{

View File

@ -31,13 +31,21 @@ template<class T, class Addr>
Foam::label Foam::IndirectListBase<T, Addr>::find
(
const T& val,
label pos
label pos,
label len
) const
{
const label len = addr_.size();
if (pos >= 0 && len)
if (pos >= 0 && pos < addr_.size())
{
// Change sub-length to (one-past) end position
// len == -1 (like std::string::npos) - search until end
if (len > 0) len += pos;
if (len < 0 || len > addr_.size())
{
len = addr_.size();
}
const T* const vals = values_.begin();
while (pos < len)
@ -62,7 +70,7 @@ Foam::label Foam::IndirectListBase<T, Addr>::rfind
label pos
) const
{
// pos == -1 has same meaning as std::string::npos - search from end
// pos == -1 (like std::string::npos) - search from end
if (pos < 0 || pos >= addr_.size())
{

View File

@ -179,11 +179,19 @@ public:
// Search
//- Is the value contained in the list?
// \param val The value to search for
// \param pos The first position to examine (default: 0, no-op if -ve)
// \param len The length of the search region (-ve until the end)
// \return true if found.
inline bool contains(const T& val, label pos = 0, label len = -1) const;
//- Find index of the first occurrence of the value.
// Any occurrences before the start pos are ignored.
// Linear search.
// \return -1 if not found.
label find(const T& val, label pos = 0) const;
// \param val The value to search for
// \param pos The first position to examine (default: 0, no-op if -ve)
// \param len The length of the search region (-ve until the end)
// \return position in list or -1 if not found.
label find(const T& val, label pos = 0, label len = -1) const;
//- Find index of the last occurrence of the value.
// Any occurrences after the end pos are ignored.
@ -191,12 +199,6 @@ public:
// \return -1 if not found.
label rfind(const T& val, label pos = -1) const;
//- Is the value contained in the list?
// Linear search from start pos until the end of the list.
// Any occurrences before the start pos are ignored.
// \return true if found.
inline bool contains(const T& val, label pos = 0) const;
// Member Operators

View File

@ -102,10 +102,11 @@ template<class T, class Addr>
inline bool Foam::IndirectListBase<T, Addr>::contains
(
const T& val,
label pos
label pos,
label len
) const
{
return (this->find(val, pos) >= 0);
return (this->find(val, pos, len) >= 0);
}

View File

@ -222,6 +222,27 @@ Foam::Istream& Foam::DynamicList<T, SizeMin>::readList(Istream& is)
);
}
}
else if (std::is_same<char, T>::value)
{
// Special treatment for char data (always binary and contiguous)
// (see List<char>::readList)
if (len)
{
const auto oldFmt = is.format(IOstreamOption::BINARY);
// read(...) includes surrounding start/end delimiters
is.read(list.data_bytes(), list.size_bytes());
is.format(oldFmt);
is.fatalCheck
(
"DynamicList<char>::readList(Istream&) : "
"reading binary block"
);
}
}
else
{
// Begin of contents marker

View File

@ -46,24 +46,42 @@ std::streamsize Foam::FixedList<T, N>::byteSize()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, unsigned N>
Foam::label Foam::FixedList<T, N>::find(const T& val, label pos) const
Foam::label Foam::FixedList<T, N>::find(const T& val) const
{
if (pos >= 0)
const auto iter = std::find(this->cbegin(), this->cend(), val);
return (iter != this->cend() ? label(iter - this->cbegin()) : label(-1));
}
template<class T, unsigned N>
Foam::label Foam::FixedList<T, N>::find
(
const T& val,
label pos,
label len
) const
{
if (pos >= 0 && pos < label(N))
{
// auto iter = std::find(this->begin(pos), this->end(), val);
// if (iter != this->end())
// {
// return label(iter - this->begin());
// }
// Change sub-length to (one-past) end position
// len == -1 (like std::string::npos) - search until end
while (pos < label(N))
if (len > 0) len += pos;
if (len < 0 || len > label(N))
{
if (this->v_[pos] == val)
{
return pos;
}
len = label(N);
}
++pos;
const auto iter = std::find
(
(this->cbegin() + pos),
(this->cbegin() + len),
val
);
if (iter != (this->cbegin() + len))
{
return label(iter - this->cbegin());
}
}
@ -74,7 +92,8 @@ Foam::label Foam::FixedList<T, N>::find(const T& val, label pos) const
template<class T, unsigned N>
Foam::label Foam::FixedList<T, N>::rfind(const T& val, label pos) const
{
// pos == -1 has same meaning as std::string::npos - search from end
// pos == -1 (like std::string::npos) - search from end
if (pos < 0 || pos >= label(N))
{
pos = label(N)-1;

View File

@ -275,11 +275,27 @@ public:
// Search
//- True if the value is contained in the list.
inline bool contains(const T& val) const;
//- Is the value contained in the list?
// \param val The value to search for
// \param pos The first position to examine (no-op if -ve)
// \param len The length of the search region (-ve until the end)
// \return true if found.
inline bool contains(const T& val, label pos, label len = -1) const;
//- Find index of the first occurrence of the value.
// Any occurrences before the start pos are ignored.
// Linear search.
// \return -1 if not found.
label find(const T& val, label pos = 0) const;
// \param val The value to search for
// \return position in list or -1 if not found.
label find(const T& val) const;
//- Find index of the first occurrence of the value.
// \param val The value to search for
// \param pos The first position to examine (no-op if -ve)
// \param len The length of the search region (-ve until the end)
// \return position in list or -1 if not found.
label find(const T& val, label pos, label len = -1) const;
//- Find index of the last occurrence of the value.
// Any occurrences after the end pos are ignored.
@ -287,12 +303,6 @@ public:
// \return position in list or -1 if not found.
label rfind(const T& val, label pos = -1) const;
//- Is the value contained in the list?
// Linear search from start pos until the end of the list.
// Any occurrences before the start pos are ignored.
// \return true if found.
inline bool contains(const T& val, label pos = 0) const;
// Edit

View File

@ -307,9 +307,22 @@ inline bool Foam::FixedList<T, N>::uniform() const
template<class T, unsigned N>
inline bool Foam::FixedList<T, N>::contains(const T& val, label pos) const
inline bool Foam::FixedList<T, N>::contains(const T& val) const
{
return (this->find(val, pos) >= 0);
const auto iter = std::find(this->cbegin(), this->cend(), val);
return (iter != this->cend());
}
template<class T, unsigned N>
inline bool Foam::FixedList<T, N>::contains
(
const T& val,
label pos,
label len
) const
{
return (this->find(val, pos, len) >= 0);
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -89,7 +89,7 @@ public:
// Constructors
//- Construct from UList, the entire size
inline explicit SubList(const UList<T>& list);
inline explicit SubList(const UList<T>& list) noexcept;
//- Construct from FixedList, the entire size
template<unsigned N>
@ -128,6 +128,47 @@ public:
);
// Member Functions
//- Reset to zero-sized and nullptr
inline UList<T>& reset(std::nullptr_t) noexcept;
//- Reset to use entire UList
inline UList<T>& reset(const UList<T>& list) noexcept;
//- Reset to use UList with sub-list size, start at 0
inline UList<T>& reset
(
const UList<T>& list,
const label subSize
);
//- Reset to use UList with sub-list size and start index
inline UList<T>& reset
(
const UList<T>& list,
const label subSize,
const label startIndex
);
//- Reset to use UList with a (start,size) range.
// The range is subsetted with the list size itself to ensure that the
// result always addresses a valid section of the list.
inline UList<T>& reset
(
const UList<T>& list,
const labelRange& range
);
//- Reset to use UList with a (start,size) range, but bypassing
//- run-time range checking.
inline UList<T>& reset
(
const labelRange& range,
const UList<T>& list
);
// Member Operators
//- Allow cast to a const List\<T\>&

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,13 +28,22 @@ License
#include "FixedList.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class T>
inline const Foam::SubList<T>& Foam::SubList<T>::null()
{
return NullObjectRef<SubList<T>>();
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T>
inline Foam::SubList<T>::SubList
(
const UList<T>& list
)
) noexcept
:
UList<T>(const_cast<T*>(list.cdata()), list.size())
{}
@ -113,9 +122,102 @@ inline Foam::SubList<T>::SubList
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T>
inline const Foam::SubList<T>& Foam::SubList<T>::null()
inline Foam::UList<T>& Foam::SubList<T>::reset(std::nullptr_t) noexcept
{
return NullObjectRef<SubList<T>>();
UList<T>::shallowCopy(nullptr, 0);
return *this;
}
template<class T>
inline Foam::UList<T>& Foam::SubList<T>::reset
(
const UList<T>& list
) noexcept
{
UList<T>::shallowCopy(list);
return *this;
}
template<class T>
inline Foam::UList<T>& Foam::SubList<T>::reset
(
const UList<T>& list,
const label subSize
)
{
#ifdef FULLDEBUG
list.checkSize(subSize);
#endif
UList<T>::shallowCopy(const_cast<T*>(list.cdata()), subSize);
return *this;
}
template<class T>
inline Foam::UList<T>& Foam::SubList<T>::reset
(
const UList<T>& list,
const label subSize,
const label startIndex
)
{
#ifdef FULLDEBUG
list.checkRange(startIndex, subSize);
#endif
UList<T>::shallowCopy
(
const_cast<T*>(list.cdata() + startIndex),
subSize
);
return *this;
}
template<class T>
inline Foam::UList<T>& Foam::SubList<T>::reset
(
const UList<T>& list,
const labelRange& range
)
{
#ifdef FULLDEBUG
// subset0() always produces valid ranges but want to check
// that the input itself was valid
list.checkRange(range.start(), range.size());
#endif
labelRange clamped(range.subset0(list.size()));
UList<T>::shallowCopy
(
const_cast<T*>(list.cdata() + clamped.start()),
clamped.size()
);
return *this;
}
template<class T>
inline Foam::UList<T>& Foam::SubList<T>::reset
(
const labelRange& range,
const UList<T>& list
)
{
#ifdef FULLDEBUG
list.checkRange(range.start(), range.size());
#endif
UList<T>::shallowCopy
(
const_cast<T*>(list.cdata() + range.start()),
range.size()
);
return *this;
}

View File

@ -177,26 +177,37 @@ std::streamsize Foam::UList<T>::byteSize() const
template<class T>
Foam::label Foam::UList<T>::find(const T& val, label pos) const
Foam::label Foam::UList<T>::find(const T& val) const
{
const label len = this->size();
const auto iter = std::find(this->cbegin(), this->cend(), val);
return (iter != this->cend() ? label(iter - this->cbegin()) : label(-1));
}
if (pos >= 0)
template<class T>
Foam::label Foam::UList<T>::find(const T& val, label pos, label len) const
{
if (pos >= 0 && pos < this->size())
{
// auto iter = std::find(this->begin(pos), this->end(), val);
// if (iter != this->end())
// {
// return label(iter - this->begin());
// }
// Change sub-length to (one-past) end position
// len == -1 (like std::string::npos) - search until end
while (pos < len)
if (len > 0) len += pos;
if (len < 0 || len > this->size())
{
if (this->v_[pos] == val)
{
return pos;
}
len = this->size();
}
++pos;
const auto iter = std::find
(
(this->cbegin() + pos),
(this->cbegin() + len),
val
);
if (iter != (this->cbegin() + len))
{
return label(iter - this->cbegin());
}
}
@ -207,7 +218,8 @@ Foam::label Foam::UList<T>::find(const T& val, label pos) const
template<class T>
Foam::label Foam::UList<T>::rfind(const T& val, label pos) const
{
// pos == -1 has same meaning as std::string::npos - search from end
// pos == -1 (like std::string::npos) - search from end
if (pos < 0 || pos >= this->size())
{
pos = this->size()-1;

View File

@ -318,11 +318,27 @@ public:
// Search
//- True if the value is contained in the list.
inline bool contains(const T& val) const;
//- Is the value contained in the list?
// \param val The value to search for
// \param pos The first position to examine (no-op if -ve)
// \param len The length of the search region (-ve until the end)
// \return true if found.
inline bool contains(const T& val, label pos, label len = -1) const;
//- Find index of the first occurrence of the value.
// Any occurrences before the start pos are ignored.
// Linear search.
// \param val The value to search for
// \return position in list or -1 if not found.
label find(const T& val, label pos = 0) const;
label find(const T& val) const;
//- Find index of the first occurrence of the value.
// \param val The value to search for
// \param pos The first position to examine (no-op if -ve)
// \param len The length of the search region (-ve until the end)
// \return position in list or -1 if not found.
label find(const T& val, label pos, label len = -1) const;
//- Find index of the last occurrence of the value.
// Any occurrences after the end pos are ignored.
@ -330,12 +346,6 @@ public:
// \return position in list or -1 if not found.
label rfind(const T& val, label pos = -1) const;
//- Is the value contained in the list?
// Linear search from start pos until the end of the list.
// Any occurrences before the start pos are ignored.
// \return true if found.
inline bool contains(const T& val, label pos = 0) const;
// Edit
@ -354,6 +364,9 @@ public:
// Copy
//- Copy the pointer and size
inline void shallowCopy(T* __restrict__ ptr, const label len) noexcept;
//- Copy the pointer and size held by the given UList
inline void shallowCopy(const UList<T>& list) noexcept;

View File

@ -304,9 +304,29 @@ inline std::streamsize Foam::UList<T>::size_bytes() const noexcept
template<class T>
inline bool Foam::UList<T>::contains(const T& val, label pos) const
inline bool Foam::UList<T>::contains(const T& val) const
{
return (this->find(val, pos) >= 0);
const auto iter = std::find(this->begin(), this->end(), val);
return (iter != this->end());
}
template<class T>
inline bool Foam::UList<T>::contains(const T& val, label pos, label len) const
{
return (this->find(val, pos, len) >= 0);
}
template<class T>
inline void Foam::UList<T>::shallowCopy
(
T* __restrict__ ptr,
const label len
) noexcept
{
size_ = len;
v_ = ptr;
}

View File

@ -187,10 +187,7 @@ Foam::Istream& Foam::UList<T>::readList(Istream& is)
<< exit(FatalIOError);
}
for (label i = 0; i < len; ++i)
{
list[i] = std::move(elems[i]);
}
std::move(elems.begin(), elems.end(), list.begin());
}
else if (tok.isLabel())
{

View File

@ -42,11 +42,12 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const std::vector<T>& list)
os << label(list.size()) << token::BEGIN_LIST;
// Contents
if (iter != last)
{
os << *iter;
while (++iter != last)
for (++iter; (iter != last); (void)++iter)
{
os << token::SPACE << *iter;
}

View File

@ -172,7 +172,7 @@ public:
#include "SubFieldI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Implementations * * * * * * * * * * * * * * //
template<class Type>
Foam::SubField<Type>