|
@@ -0,0 +1,236 @@ |
|
|
|
|
|
/*!
|
|
|
|
|
|
* \file utl/container/id.h
|
|
|
|
|
|
* \brief A container for device ID's
|
|
|
|
|
|
*
|
|
|
|
|
|
* Copyright (C) 2018 Christos Choutouridis
|
|
|
|
|
|
*
|
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
|
|
|
|
* published by the Free Software Foundation, either version 3
|
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This program 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 Lesser General Public License for more details.
|
|
|
|
|
|
*
|
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef __utl_container_id_h__
|
|
|
|
|
|
#define __utl_container_id_h__
|
|
|
|
|
|
|
|
|
|
|
|
#include <utl/impl/impl.h>
|
|
|
|
|
|
#include <utl/container/array.h>
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
|
|
namespace utl {
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* \ingroup containers
|
|
|
|
|
|
* \brief
|
|
|
|
|
|
* id container traits helper
|
|
|
|
|
|
*/
|
|
|
|
|
|
//! @{
|
|
|
|
|
|
template <typename _Tp, size_t _Nm>
|
|
|
|
|
|
struct id_traits {
|
|
|
|
|
|
typedef _Tp type[_Nm];
|
|
|
|
|
|
|
|
|
|
|
|
static constexpr _Tp& Ref (const type& t, size_t n) noexcept {
|
|
|
|
|
|
return const_cast<_Tp&> (t[n]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static constexpr _Tp* Ptr(const type& t) noexcept {
|
|
|
|
|
|
return const_cast<_Tp*> (t);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <typename _Tp>
|
|
|
|
|
|
struct id_traits<_Tp, 0> {
|
|
|
|
|
|
struct type { };
|
|
|
|
|
|
|
|
|
|
|
|
static constexpr _Tp& Ref(const type& t, size_t n) noexcept {
|
|
|
|
|
|
return *static_cast<_Tp*>(nullptr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static constexpr _Tp* Ptr(const type& t) noexcept {
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
//! @{
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* \ingroup containers
|
|
|
|
|
|
* \brief
|
|
|
|
|
|
* A standard container for storing IDs as a fixed size
|
|
|
|
|
|
* sequence of bytes. This type is based on etl::array
|
|
|
|
|
|
* Meets the requirements of:
|
|
|
|
|
|
* <a href="tables.html#65">container</a>,
|
|
|
|
|
|
* <a href="tables.html#66">reversible container</a>,
|
|
|
|
|
|
* <a href="tables.html#67">sequence</a>.
|
|
|
|
|
|
* Sets support random access iterators.
|
|
|
|
|
|
* \tparam _Tp The base type
|
|
|
|
|
|
* \tparam _Nm Number of bytes.
|
|
|
|
|
|
*/
|
|
|
|
|
|
template <typename _Tp, size_t _Nm>
|
|
|
|
|
|
struct id_t {
|
|
|
|
|
|
using value_type = _Tp;
|
|
|
|
|
|
using pointer = value_type*;
|
|
|
|
|
|
using const_pointer = const value_type*;
|
|
|
|
|
|
using reference = value_type&;
|
|
|
|
|
|
using const_reference = const value_type&;
|
|
|
|
|
|
using iterator = value_type*;
|
|
|
|
|
|
using const_iterator = const value_type*;
|
|
|
|
|
|
using size_type = size_t;
|
|
|
|
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
|
|
using reverse_iterator = std::reverse_iterator <iterator>;
|
|
|
|
|
|
using const_reverse_iterator
|
|
|
|
|
|
= std::reverse_iterator <const_iterator>;
|
|
|
|
|
|
|
|
|
|
|
|
// type and data
|
|
|
|
|
|
using traits_t = id_traits<_Tp, _Nm>;
|
|
|
|
|
|
typename traits_t::type _data;
|
|
|
|
|
|
|
|
|
|
|
|
// No explicit construct/copy/destroy for aggregate type.
|
|
|
|
|
|
|
|
|
|
|
|
// DR 776 (std::array)
|
|
|
|
|
|
void fill (const value_type& v) { std::fill_n (begin(), size(), v); }
|
|
|
|
|
|
|
|
|
|
|
|
void swap (id_t& other) noexcept {
|
|
|
|
|
|
std::swap_ranges (begin(), end(), other.begin());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! \name Iterators.
|
|
|
|
|
|
//!@{
|
|
|
|
|
|
iterator begin() noexcept { return iterator (data()); }
|
|
|
|
|
|
const_iterator begin() const noexcept { return const_iterator (data()); }
|
|
|
|
|
|
iterator end() noexcept { return iterator (data() + _Nm); }
|
|
|
|
|
|
const_iterator end() const noexcept { return const_iterator (data() + _Nm); }
|
|
|
|
|
|
const_iterator cbegin() const noexcept { return const_iterator (data()); }
|
|
|
|
|
|
const_iterator cend() const noexcept { return const_iterator (data() + _Nm); }
|
|
|
|
|
|
|
|
|
|
|
|
reverse_iterator rbegin() noexcept { return reverse_iterator (end()); }
|
|
|
|
|
|
reverse_iterator rend() noexcept { return reverse_iterator (begin()); }
|
|
|
|
|
|
const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator (end()); }
|
|
|
|
|
|
const_reverse_iterator rend() const noexcept { return const_reverse_iterator (begin()); }
|
|
|
|
|
|
const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator (end()); }
|
|
|
|
|
|
const_reverse_iterator crend() const noexcept { return const_reverse_iterator (begin()); }
|
|
|
|
|
|
//!@{
|
|
|
|
|
|
//! \name Capacity.
|
|
|
|
|
|
//!@{
|
|
|
|
|
|
constexpr size_type size() const noexcept { return _Nm; }
|
|
|
|
|
|
constexpr size_type max_size() const noexcept { return _Nm; }
|
|
|
|
|
|
constexpr bool empty() const noexcept { return size() == 0; }
|
|
|
|
|
|
//!@{
|
|
|
|
|
|
|
|
|
|
|
|
//! \name Element access.
|
|
|
|
|
|
//!@{
|
|
|
|
|
|
|
|
|
|
|
|
//! Operator []
|
|
|
|
|
|
reference operator[] (size_type n) noexcept {
|
|
|
|
|
|
return traits_t::Ref (_data, n);
|
|
|
|
|
|
}
|
|
|
|
|
|
//! Operator [] for const
|
|
|
|
|
|
constexpr const_reference operator[] (size_type n) const noexcept {
|
|
|
|
|
|
return traits_t::Ref (_data, n);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* Boundary check dereference operator.
|
|
|
|
|
|
* If out of bounds, abort (for now).
|
|
|
|
|
|
*/
|
|
|
|
|
|
reference at (size_type n) noexcept {
|
|
|
|
|
|
if (n < _Nm)
|
|
|
|
|
|
return traits_t::Ref (_data, n);
|
|
|
|
|
|
else
|
|
|
|
|
|
abort ();
|
|
|
|
|
|
}
|
|
|
|
|
|
//! Compile time boundary check dereference operator.
|
|
|
|
|
|
constexpr const_reference at (size_type n) const noexcept {
|
|
|
|
|
|
static_assert ((n < _Nm), "id_t::at: out of range");
|
|
|
|
|
|
return traits_t::Ref (_data, n);
|
|
|
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* Read a bit position from a id
|
|
|
|
|
|
* \param bit The bit location we want to read
|
|
|
|
|
|
*/
|
|
|
|
|
|
constexpr bool bit (uint8_t bit) const noexcept {
|
|
|
|
|
|
value_type one = 1;
|
|
|
|
|
|
uint8_t den = 8*sizeof(_Tp)/sizeof(uint8_t);
|
|
|
|
|
|
return traits_t::Ref (_data, bit/den) & (one << ((bit % den)-1));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* Write/modify a bit position from a id
|
|
|
|
|
|
* \param bit The bit location we want to set
|
|
|
|
|
|
* \param v The value we want to set
|
|
|
|
|
|
*/
|
|
|
|
|
|
void bit (uint8_t bit, bool v) noexcept {
|
|
|
|
|
|
value_type one = 1;
|
|
|
|
|
|
uint8_t den = 8*sizeof(_Tp)/sizeof(uint8_t);
|
|
|
|
|
|
if (v) traits_t::Ref (_data, bit/den) |= one << ((bit % den)-1);
|
|
|
|
|
|
else traits_t::Ref (_data, bit/den) &= ~one << ((bit % den)-1);
|
|
|
|
|
|
}
|
|
|
|
|
|
// first item
|
|
|
|
|
|
reference front () noexcept {
|
|
|
|
|
|
return *begin ();
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr const_reference front () const noexcept {
|
|
|
|
|
|
return traits_t::Ref (_data, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Last item
|
|
|
|
|
|
reference back () noexcept {
|
|
|
|
|
|
return _Nm ? *(end() - 1) : *end();
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr const_reference back () const noexcept {
|
|
|
|
|
|
return _Nm ? traits_t::Ref (_data, _Nm - 1)
|
|
|
|
|
|
: traits_t::Ref (_data, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Pointer to data
|
|
|
|
|
|
pointer data () noexcept { return traits_t::Ptr (_data); }
|
|
|
|
|
|
const_pointer data () const noexcept { return traits_t::Ptr (_data); }
|
|
|
|
|
|
//!<@}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//! \name device ID comparisons.
|
|
|
|
|
|
//!@{
|
|
|
|
|
|
template <typename _Tp, size_t _Nm>
|
|
|
|
|
|
inline bool operator== (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
|
|
|
|
|
|
return std::equal (lhs.begin(), lhs.end(), rhs.begin());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename _Tp, size_t _Nm>
|
|
|
|
|
|
inline bool operator!= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
|
|
|
|
|
|
return !(lhs == rhs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename _Tp, size_t _Nm>
|
|
|
|
|
|
inline bool operator< (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
|
|
|
|
|
|
// MSB plays bigger role in comparison
|
|
|
|
|
|
return std::lexicographical_compare(lhs.rbegin(), lhs.rend(), rhs.rbegin(), rhs.rend());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename _Tp, size_t _Nm>
|
|
|
|
|
|
inline bool operator> (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
|
|
|
|
|
|
return rhs < lhs;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename _Tp, size_t _Nm>
|
|
|
|
|
|
inline bool operator<= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
|
|
|
|
|
|
return !(lhs > rhs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename _Tp, size_t _Nm>
|
|
|
|
|
|
inline bool operator>= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
|
|
|
|
|
|
return !(lhs < rhs);
|
|
|
|
|
|
}
|
|
|
|
|
|
//!@}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace utl
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* __utl_container_id_h__ */
|