diff --git a/include/utl/container/id.h b/include/utl/container/id.h new file mode 100644 index 0000000..1b12dcf --- /dev/null +++ b/include/utl/container/id.h @@ -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 . + * + */ + +#ifndef __utl_container_id_h__ +#define __utl_container_id_h__ + +#include +#include +#include + +namespace utl { + + /*! + * \ingroup containers + * \brief + * id container traits helper + */ + //! @{ + template + 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 + 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: + * container, + * reversible container, + * sequence. + * Sets support random access iterators. + * \tparam _Tp The base type + * \tparam _Nm Number of bytes. + */ + template + 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 ; + using const_reverse_iterator + = std::reverse_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 + 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 + inline bool operator!= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) { + return !(lhs == rhs); + } + + template + 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 + inline bool operator> (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) { + return rhs < lhs; + } + + template + inline bool operator<= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) { + return !(lhs > rhs); + } + + template + 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__ */