/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
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
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template
inline constexpr unsigned int Foam::PackedList::max_bits()
{
return sizeof(StorageType)*CHAR_BIT - 1;
}
template
inline constexpr unsigned int Foam::PackedList::max_value()
{
return (1u << nBits) - 1;
}
template
inline constexpr unsigned int Foam::PackedList::packing()
{
return sizeof(StorageType)*CHAR_BIT / nBits;
}
template
inline constexpr unsigned int Foam::PackedList::maskLower
(
unsigned offset
)
{
// Return (1u << (nBits * offset)) - 1;
// The next one works more reliably with overflows
// eg, when compiled without optimization
return (~0u >> (sizeof(StorageType)*CHAR_BIT - nBits * offset));
}
template
inline constexpr Foam::label Foam::PackedList::packedLength
(
const label nElem
)
{
return (nElem + packing() - 1) / packing();
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
namespace Foam
{
// Template specialization for bool entries
template<>
inline unsigned int Foam::PackedList<1>::readValue(Istream& is)
{
return readBool(is);
}
// Template specialization for bool entries
template<>
inline void Foam::PackedList<1>::setPair(Istream& is)
{
set(readLabel(is), true);
}
// Template specialization for bool entries
template<>
inline bool Foam::PackedList<1>::iteratorBase::writeIfSet(Ostream& os) const
{
if (this->get())
{
os << index_;
return true;
}
return false;
}
}
template
inline unsigned int Foam::PackedList::readValue(Istream& is)
{
const unsigned int val = readLabel(is);
if (val > max_value())
{
FatalIOErrorInFunction(is)
<< "Out-of-range value " << val << " for PackedList<" << nBits
<< ">. Maximum permitted value is " << max_value() << "."
<< exit(FatalIOError);
}
return val;
}
template
inline void Foam::PackedList::setPair(Istream& is)
{
is.readBegin("Tuple2");
const label ind = readLabel(is);
const unsigned int val = readLabel(is);
is.readEnd("Tuple2");
if (val > max_value())
{
FatalIOErrorInFunction(is)
<< "Out-of-range value " << val << " for PackedList<" << nBits
<< "> at index " << ind
<< ". Maximum permitted value is " << max_value() << "."
<< exit(FatalIOError);
}
set(ind, val);
is.check(FUNCTION_NAME);
}
template
inline bool Foam::PackedList::iteratorBase::writeIfSet(Ostream& os) const
{
const label val = this->get();
if (val)
{
os << token::BEGIN_LIST
<< index_ << token::SPACE << val
<< token::END_LIST;
return true;
}
return false;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template
inline Foam::PackedList::PackedList()
:
PackedListCore(),
StorageList(),
size_(0)
{}
template
inline Foam::PackedList::PackedList(const label size)
:
PackedListCore(),
StorageList(packedLength(size), 0u),
size_(size)
{}
template
inline Foam::PackedList::PackedList
(
const label size,
const unsigned int val
)
:
PackedListCore(),
StorageList(packedLength(size), 0u),
size_(size)
{
if (val)
{
operator=(val);
}
}
template
inline Foam::PackedList::PackedList(Istream& is)
:
PackedListCore(),
StorageList(),
size_(0)
{
read(is);
}
template
inline Foam::PackedList::PackedList(const PackedList& lst)
:
PackedListCore(),
StorageList(lst),
size_(lst.size_)
{}
template
inline Foam::PackedList::PackedList(PackedList&& lst)
:
PackedListCore(),
StorageList(),
size_(0)
{
transfer(lst);
}
template
inline Foam::PackedList::PackedList(const labelUList& lst)
:
PackedListCore(),
StorageList(packedLength(lst.size()), 0u),
size_(lst.size())
{
const label len = lst.size();
for (label i = 0; i < len; ++i)
{
set(i, lst[i]);
}
}
template
inline Foam::PackedList::PackedList(const labelUIndList& lst)
:
PackedListCore(),
StorageList(packedLength(lst.size()), 0u),
size_(lst.size())
{
const label len = lst.size();
for (label i = 0; i < len; ++i)
{
set(i, lst[i]);
}
}
template
inline Foam::autoPtr>
Foam::PackedList::clone() const
{
return autoPtr>(new PackedList(*this));
}
// * * * * * * * * * * * * * * * * Iterators * * * * * * * * * * * * * * * * //
template
inline Foam::PackedList::iteratorBase::iteratorBase()
:
list_(nullptr),
index_(0)
{}
template
inline Foam::PackedList::iteratorBase::iteratorBase
(
const PackedList* lst,
const label i
)
:
list_(const_cast*>(lst)),
index_(i)
{}
template
inline unsigned int
Foam::PackedList::iteratorBase::get() const
{
const unsigned int seg = index_ / packing();
const unsigned int off = index_ % packing();
const unsigned int& stored = list_->StorageList::operator[](seg);
return (stored >> (nBits * off)) & max_value();
}
template
inline bool
Foam::PackedList::iteratorBase::set(const unsigned int val)
{
const unsigned int seg = index_ / packing();
const unsigned int off = index_ % packing();
const unsigned int startBit = nBits * off;
const unsigned int mask = max_value() << startBit;
unsigned int& stored = list_->StorageList::operator[](seg);
const unsigned int prev = stored;
if (val >= max_value())
{
// Overflow is max_value, fill everything
stored |= mask;
}
else
{
stored &= ~mask;
stored |= mask & (val << startBit);
}
return prev != stored;
}
template
inline Foam::label Foam::PackedList::iteratorBase::key() const
{
return index_;
}
template
inline bool Foam::PackedList::iteratorBase::operator==
(
const iteratorBase& iter
) const
{
return this->get() == iter.get();
}
template
inline bool Foam::PackedList::iteratorBase::operator!=
(
const iteratorBase& iter
) const
{
return this->get() != iter.get();
}
template
inline void Foam::PackedList::iteratorBase::operator=
(
const iteratorBase& iter
)
{
const unsigned int val = iter.get();
this->set(val);
}
template
inline void Foam::PackedList::iteratorBase::operator=
(
const unsigned int val
)
{
// Lazy evaluation - increase size on assigment
if (index_ >= list_->size_)
{
list_->resize(index_ + 1);
}
this->set(val);
}
template
inline Foam::PackedList::iteratorBase::operator
unsigned int () const
{
// Lazy evaluation - return 0 for out-of-range
if (index_ >= list_->size_)
{
return 0;
}
return this->get();
}
template
inline Foam::PackedList::iterator::iterator()
:
iteratorBase()
{}
template
inline Foam::PackedList::const_iterator::const_iterator()
:
iteratorBase()
{}
template
inline Foam::PackedList::iterator::iterator
(
const iteratorBase& iter
)
:
iteratorBase(iter)
{
// Avoid going past end()
// eg, iter = iterator(list, Inf)
if (this->index_ > this->list_->size_)
{
this->index_ = this->list_->size_;
}
}
template
inline Foam::PackedList::const_iterator::const_iterator
(
const iteratorBase& iter
)
:
iteratorBase(iter)
{
// Avoid going past end()
// eg, iter = iterator(list, Inf)
if (this->index_ > this->list_->size_)
{
this->index_ = this->list_->size_;
}
}
template
inline Foam::PackedList::iterator::iterator
(
const PackedList* lst,
const label i
)
:
iteratorBase(lst, i)
{}
template
inline Foam::PackedList::const_iterator::const_iterator
(
const PackedList* lst,
const label i
)
:
iteratorBase(lst, i)
{}
template
inline Foam::PackedList::const_iterator::const_iterator
(
const iterator& iter
)
:
iteratorBase(static_cast(iter))
{}
template
inline bool Foam::PackedList::iterator::operator==
(
const iteratorBase& iter
) const
{
return this->index_ == iter.index_;
}
template
inline bool Foam::PackedList::iterator::operator!=
(
const iteratorBase& iter
) const
{
return this->index_ != iter.index_;
}
template
inline bool Foam::PackedList::const_iterator::operator==
(
const iteratorBase& iter
) const
{
return this->index_ == iter.index_;
}
template
inline bool Foam::PackedList::const_iterator::operator!=
(
const iteratorBase& iter
) const
{
return this->index_ != iter.index_;
}
template
inline void Foam::PackedList::iterator::operator=
(
const iteratorBase& iter
)
{
this->list_ = iter.list_;
this->index_ = iter.index_;
// Avoid going past end()
// eg, iter = iterator(list, Inf)
if (this->index_ > this->list_->size_)
{
this->index_ = this->list_->size_;
}
}
template
inline void Foam::PackedList::const_iterator::operator=
(
const iteratorBase& iter
)
{
this->list_ = iter.list_;
this->index_ = iter.index_;
// Avoid going past end()
// eg, iter = iterator(list, Inf)
if (this->index_ > this->list_->size_)
{
this->index_ = this->list_->size_;
}
return *this;
}
template
inline typename Foam::PackedList::iterator&
Foam::PackedList::iterator::operator++()
{
++this->index_;
return *this;
}
template
inline typename Foam::PackedList::const_iterator&
Foam::PackedList::const_iterator::operator++()
{
++this->index_;
return *this;
}
template
inline typename Foam::PackedList::iterator
Foam::PackedList::iterator::operator++(int)
{
iterator old = *this;
++this->index_;
return old;
}
template
inline typename Foam::PackedList::const_iterator
Foam::PackedList::const_iterator::operator++(int)
{
const_iterator old = *this;
++this->index_;
return old;
}
template
inline typename Foam::PackedList::iterator&
Foam::PackedList::iterator::operator--()
{
--this->index_;
return *this;
}
template
inline typename Foam::PackedList::const_iterator&
Foam::PackedList::const_iterator::operator--()
{
--this->index_;
return *this;
}
template
inline typename Foam::PackedList::iterator
Foam::PackedList::iterator::operator--(int)
{
iterator old = *this;
--this->index_;
return old;
}
template
inline typename Foam::PackedList::const_iterator
Foam::PackedList::const_iterator::operator--(int)
{
const_iterator old = *this;
--this->index_;
return old;
}
template
inline typename Foam::PackedList::iteratorBase&
Foam::PackedList::iterator::operator*()
{
return static_cast(*this);
}
template
inline typename Foam::PackedList::iteratorBase&
Foam::PackedList::iterator::operator()()
{
return static_cast(*this);
}
template
inline unsigned int
Foam::PackedList::const_iterator::operator*() const
{
return this->get();
}
template
inline unsigned int
Foam::PackedList::const_iterator::operator()() const
{
return this->get();
}
template
inline typename Foam::PackedList::iterator
Foam::PackedList::begin()
{
return iterator(this, 0);
}
template
inline typename Foam::PackedList::const_iterator
Foam::PackedList::begin() const
{
return const_iterator(this, 0);
}
template
inline typename Foam::PackedList::const_iterator
Foam::PackedList::cbegin() const
{
return const_iterator(this, 0);
}
template
inline typename Foam::PackedList::iterator
Foam::PackedList::end()
{
return iterator(this, size_);
}
template
inline typename Foam::PackedList::const_iterator
Foam::PackedList::end() const
{
return const_iterator(this, size_);
}
template
inline typename Foam::PackedList::const_iterator
Foam::PackedList::cend() const
{
return const_iterator(this, size_);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template
inline Foam::label Foam::PackedList::size() const
{
return size_;
}
template
inline bool Foam::PackedList::empty() const
{
return !size_;
}
template
inline void Foam::PackedList::resize
(
const label newSize,
const unsigned int val
)
{
reserve(newSize);
const label oldSize = size_;
size_ = newSize;
if (size_ > oldSize)
{
// Fill new elements or newly exposed elements
if (val)
{
// Fill value for complete segments
unsigned int fill = val;
if (val >= max_value())
{
// Fill everything
fill = maskLower(packing());
}
else
{
for (unsigned int i = 1; i < packing(); ++i)
{
fill |= (fill << nBits);
}
}
// Fill in complete segments
const label oldLen = packedLength(oldSize);
const label newLen = packedLength(size_);
for (label i=oldLen; i < newLen; ++i)
{
StorageList::operator[](i) = fill;
}
// Finish previous partial segment, preserve existing value
{
const unsigned int off = oldSize % packing();
if (off)
{
const unsigned int seg = oldSize / packing();
const unsigned int mask = maskLower(off);
StorageList::operator[](seg) &= mask;
StorageList::operator[](seg) |= ~mask & fill;
}
}
// Mask off the (new) final partial segment
{
const unsigned int off = size_ % packing();
if (off)
{
const unsigned int seg = size_ / packing();
StorageList::operator[](seg) &= maskLower(off);
}
}
}
}
else if (size_ < oldSize)
{
// Resize shrinking
// - clear newly exposed elements
// Fill in complete segments
const label oldLen = packedLength(oldSize);
const label newLen = packedLength(size_);
for (label i=newLen; i < oldLen; ++i)
{
StorageList::operator[](i) = 0u;
}
// Mask off the final partial segment
{
const unsigned int off = size_ % packing();
if (off)
{
const unsigned int seg = size_ / packing();
StorageList::operator[](seg) &= maskLower(off);
}
}
}
}
template
inline void Foam::PackedList::setSize
(
const label newSize,
const unsigned int val
)
{
resize(newSize, val);
}
template
inline Foam::label Foam::PackedList::capacity() const
{
return packing() * StorageList::size();
}
template
inline void Foam::PackedList::setCapacity(const label nElem)
{
StorageList::setSize(packedLength(nElem), 0u);
// Truncate addressed size too
if (size_ > nElem)
{
size_ = nElem;
// Mask off the final partial segment
const unsigned int off = size_ % packing();
if (off)
{
const unsigned int seg = size_ / packing();
StorageList::operator[](seg) &= maskLower(off);
}
}
}
template
inline void Foam::PackedList::reserve(const label nElem)
{
const label len = packedLength(nElem);
// Allocate more capacity if necessary
if (len > StorageList::size())
{
StorageList::setSize
(
max
(
len,
// SizeInc=0, SizeMult=2, SizeDiv=1
2 * StorageList::size()
),
0u
);
}
}
template
inline void Foam::PackedList::reset()
{
StorageList::operator=(0u);
}
template
inline void Foam::PackedList::clear()
{
reset();
size_ = 0;
}
template
inline void Foam::PackedList::clearStorage()
{
StorageList::clear();
size_ = 0;
}
template
inline void Foam::PackedList::shrink()
{
// Any uneed space allocated?
const label len = packedLength();
if (len < StorageList::size())
{
StorageList::setSize(len);
}
}
template
inline Foam::List& Foam::PackedList::storage()
{
return static_cast(*this);
}
template
inline const Foam::List& Foam::PackedList::storage() const
{
return static_cast(*this);
}
template
inline Foam::label Foam::PackedList::packedLength() const
{
return packedLength(size_);
}
template
inline std::streamsize Foam::PackedList::byteSize() const
{
return packedLength() * sizeof(StorageType);
}
template
inline void Foam::PackedList::transfer(PackedList& lst)
{
size_ = lst.size_;
lst.size_ = 0;
StorageList::transfer(lst);
}
template
inline unsigned int Foam::PackedList::get(const label i) const
{
// Lazy evaluation - return 0 for out-of-range
if (i < 0 || i >= size_)
{
return 0u;
}
return iteratorBase(this, i).get();
}
template
inline unsigned int Foam::PackedList::operator[](const label i) const
{
return get(i);
}
template
inline bool Foam::PackedList::set
(
const label i,
const unsigned int val
)
{
if (i < 0)
{
// Lazy evaluation - ignore out-of-bounds
return false;
}
else if (i >= size_)
{
if (!val)
{
// Same as unset out-of-bounds = noop
return false;
}
// Lazy evaluation - increase size on assigment
resize(i + 1);
}
return iteratorBase(this, i).set(val);
}
template
inline bool Foam::PackedList::unset(const label i)
{
// Unset out-of-bounds = noop
if (i < 0 || i >= size_)
{
return false;
}
return iteratorBase(this, i).set(0u);
}
template
inline Foam::PackedList&
Foam::PackedList::append(const unsigned int val)
{
const label idx = size_;
reserve(idx + 1);
size_++;
iteratorBase(this, idx).set(val);
return *this;
}
template
inline unsigned int Foam::PackedList::remove()
{
// Location of last element and simultaneously the new size
const label idx = size_ - 1;
if (idx < 0)
{
FatalErrorInFunction
<< "List is empty" << abort(FatalError);
}
const unsigned int val = iteratorBase(this, idx).get();
resize(idx);
return val;
}
template
inline typename Foam::PackedList::iteratorBase
Foam::PackedList::operator[](const label i)
{
return iteratorBase(this, i);
}
template
inline void Foam::PackedList::operator=(const unsigned int val)
{
const label packLen = packedLength();
if (val && size_)
{
unsigned int fill = val;
if (val >= max_value())
{
// Fill everything
fill = maskLower(packing());
}
else
{
for (unsigned int i = 1; i < packing(); ++i)
{
fill |= (fill << nBits);
}
}
for (label i=0; i < packLen; ++i)
{
StorageList::operator[](i) = fill;
}
// Mask off the final partial segment
{
const unsigned int off = size_ % packing();
if (off)
{
const unsigned int seg = size_ / packing();
StorageList::operator[](seg) &= maskLower(off);
}
}
}
else
{
for (label i=0; i < packLen; ++i)
{
StorageList::operator[](i) = 0u;
}
}
}
// ************************************************************************* //