qpcpp/include/qpset.hpp

198 lines
6.5 KiB
C++
Raw Normal View History

2015-05-14 16:05:04 -04:00
/// @file
/// @brief platform-independent priority sets of 8 or 64 elements.
/// @ingroup qf
/// @cond
2014-04-13 21:35:34 -04:00
///***************************************************************************
2020-03-17 21:33:58 -04:00
/// Last updated for version 6.8.0
/// Last updated on 2020-01-20
2014-04-13 21:35:34 -04:00
///
2019-01-14 12:06:15 -05:00
/// Q u a n t u m L e a P s
/// ------------------------
/// Modern Embedded Software
2014-04-13 21:35:34 -04:00
///
2019-01-14 12:06:15 -05:00
/// Copyright (C) 2005-2019 Quantum Leaps. All rights reserved.
2012-08-14 18:00:48 -04:00
///
2014-04-13 21:35:34 -04:00
/// This program is open source 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.
///
/// Alternatively, this program may be distributed and modified under the
/// terms of Quantum Leaps commercial licenses, which expressly supersede
/// the GNU General Public License and are specifically designed for
/// licensees interested in retaining the proprietary status of their code.
///
/// 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 General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
2019-10-27 12:26:31 -04:00
/// along with this program. If not, see <www.gnu.org/licenses>.
2014-04-13 21:35:34 -04:00
///
/// Contact information:
2019-12-31 15:56:23 -05:00
/// <www.state-machine.com/licensing>
2019-10-27 12:26:31 -04:00
/// <info@state-machine.com>
2014-04-13 21:35:34 -04:00
///***************************************************************************
2015-05-14 16:05:04 -04:00
/// @endcond
2014-04-13 21:35:34 -04:00
2019-10-27 12:26:31 -04:00
#ifndef QPSET_HPP
#define QPSET_HPP
2012-08-14 18:00:48 -04:00
2019-01-14 12:06:15 -05:00
namespace QP {
2019-12-31 15:56:23 -05:00
#ifndef QF_MAX_ACTIVE
// default value when NOT defined
2020-03-17 21:33:58 -04:00
#define QF_MAX_ACTIVE 32U
2019-12-31 15:56:23 -05:00
#endif
2020-03-17 21:33:58 -04:00
#if (QF_MAX_ACTIVE < 1U) || (64U < QF_MAX_ACTIVE)
#error "QF_MAX_ACTIVE out of range. Valid range is 1U..64U"
#elif (QF_MAX_ACTIVE <= 8U)
using QPSetBits = std::uint8_t;
#elif (QF_MAX_ACTIVE <= 16U)
using QPSetBits = std::uint16_t;
2019-01-14 12:06:15 -05:00
#else
//! bitmask for the internal representation of QPSet elements
2020-03-17 21:33:58 -04:00
using QPSetBits = std::uint32_t;
2016-09-29 19:54:50 -04:00
#endif
2012-08-14 18:00:48 -04:00
2019-01-14 12:06:15 -05:00
//****************************************************************************
// Log-base-2 calculations ...
#ifndef QF_LOG2
2020-03-17 21:33:58 -04:00
extern "C" std::uint_fast8_t QF_LOG2(QPSetBits x) noexcept;
2019-01-14 12:06:15 -05:00
#endif // QF_LOG2
2012-08-14 18:00:48 -04:00
2013-10-10 20:01:51 -04:00
//****************************************************************************
2016-09-29 19:54:50 -04:00
#if (QF_MAX_ACTIVE <= 32)
//! Priority Set of up to 32 elements */
///
2012-08-14 18:00:48 -04:00
/// The priority set represents the set of active objects that are ready to
2016-09-29 19:54:50 -04:00
/// run and need to be considered by the scheduling algorithm. The set is
2019-12-31 15:56:23 -05:00
/// capable of storing up to 32 priority levels. QP::QPSet is specifically
/// declared as a POD (Plain Old Data) for ease of initialization and
/// interfacing with plain "C" code.
2016-09-29 19:54:50 -04:00
///
2019-12-31 15:56:23 -05:00
struct QPSet {
2012-08-14 18:00:48 -04:00
2019-01-14 12:06:15 -05:00
QPSetBits volatile m_bits; //!< bitmask with a bit for each element
2012-08-14 18:00:48 -04:00
2016-09-29 19:54:50 -04:00
//! Makes the priority set @p me_ empty.
2020-03-17 21:33:58 -04:00
void setEmpty(void) noexcept {
m_bits = 0U;
2016-09-29 19:54:50 -04:00
}
//! Evaluates to true if the priority set is empty
2020-03-17 21:33:58 -04:00
bool isEmpty(void) const noexcept {
return (m_bits == 0U);
2012-08-14 18:00:48 -04:00
}
2016-09-29 19:54:50 -04:00
//! Evaluates to true if the priority set is not empty
2020-03-17 21:33:58 -04:00
bool notEmpty(void) const noexcept {
return (m_bits != 0U);
2012-08-14 18:00:48 -04:00
}
2014-04-13 21:35:34 -04:00
//! the function evaluates to TRUE if the priority set has the element n.
2020-03-17 21:33:58 -04:00
bool hasElement(std::uint_fast8_t const n) const noexcept {
return (m_bits & (1U << (n - 1U))) != 0U;
2012-08-14 18:00:48 -04:00
}
2019-01-14 12:06:15 -05:00
//! insert element @p n into the set, n = 1..QF_MAX_ACTIVE
2020-03-17 21:33:58 -04:00
void insert(std::uint_fast8_t const n) noexcept {
m_bits |= (1U << (n - 1U));
2012-08-14 18:00:48 -04:00
}
2019-01-14 12:06:15 -05:00
//! remove element @p n from the set, n = 1..QF_MAX_ACTIVE
2019-12-31 15:56:23 -05:00
/// @note
/// intentionally misspelled ("rmove") to avoid collision with
/// the C++ standard library facility "remove"
2020-03-17 21:33:58 -04:00
void rmove(std::uint_fast8_t const n) noexcept {
m_bits &=
static_cast<QPSetBits>(~(static_cast<QPSetBits>(1) << (n - 1U)));
2012-08-14 18:00:48 -04:00
}
2020-03-17 21:33:58 -04:00
std::uint_fast8_t findMax(void) const noexcept {
2016-09-29 19:54:50 -04:00
return QF_LOG2(m_bits);
2012-08-14 18:00:48 -04:00
}
};
2020-03-17 21:33:58 -04:00
#else // QF_MAX_ACTIVE > 32U
2016-09-29 19:54:50 -04:00
//! Priority Set of up to 64 elements
///
2012-08-14 18:00:48 -04:00
/// The priority set represents the set of active objects that are ready to
2016-09-29 19:54:50 -04:00
/// run and need to be considered by the scheduling algorithm. The set is
2019-12-31 15:56:23 -05:00
/// capable of storing up to 64 priority levels. QP::QPSet is specifically
/// declared as a POD (Plain Old Data) for ease of initialization and
/// interfacing with plain "C" code.
2016-09-29 19:54:50 -04:00
///
2019-12-31 15:56:23 -05:00
struct QPSet {
2016-09-29 19:54:50 -04:00
2020-03-17 21:33:58 -04:00
//! Two 32-bit bitmasks with a bit for each element
std::uint32_t volatile m_bits[2];
2012-08-14 18:00:48 -04:00
2016-09-29 19:54:50 -04:00
//! Makes the priority set @p me_ empty.
2020-03-17 21:33:58 -04:00
void setEmpty(void) noexcept {
m_bits[0] = 0U;
m_bits[1] = 0U;
2016-09-29 19:54:50 -04:00
}
//! Evaluates to true if the priority set is empty
// the following logic avoids UB in volatile access for MISRA compliantce
2020-03-17 21:33:58 -04:00
bool isEmpty(void) const noexcept {
return (m_bits[0] == 0U) ? (m_bits[1] == 0U) : false;
2012-08-14 18:00:48 -04:00
}
2016-09-29 19:54:50 -04:00
//! Evaluates to true if the priority set is not empty
// the following logic avoids UB in volatile access for MISRA compliantce
2020-03-17 21:33:58 -04:00
bool notEmpty(void) const noexcept {
return (m_bits[0] != 0U) ? true : (m_bits[1] != 0U);
2012-08-14 18:00:48 -04:00
}
2014-04-13 21:35:34 -04:00
//! the function evaluates to TRUE if the priority set has the element n.
2020-03-17 21:33:58 -04:00
bool hasElement(std::uint_fast8_t const n) const noexcept {
return (n <= 32U)
? ((m_bits[0] & (static_cast<std::uint32_t>(1) << (n - 1U)))
!= 0U)
: ((m_bits[1] & (static_cast<std::uint32_t>(1) << (n - 33U)))
!= 0U);
2012-08-14 18:00:48 -04:00
}
2015-05-14 16:05:04 -04:00
//! insert element @p n into the set, n = 1..64
2020-03-17 21:33:58 -04:00
void insert(std::uint_fast8_t const n) noexcept {
if (n <= 32U) {
m_bits[0] |= (static_cast<std::uint32_t>(1) << (n - 1U));
2016-09-29 19:54:50 -04:00
}
else {
2020-03-17 21:33:58 -04:00
m_bits[1] |= (static_cast<std::uint32_t>(1) << (n - 33U));
2016-09-29 19:54:50 -04:00
}
2012-08-14 18:00:48 -04:00
}
2015-05-14 16:05:04 -04:00
//! remove element @p n from the set, n = 1..64
2019-12-31 15:56:23 -05:00
/// @note
/// intentionally misspelled ("rmove") to avoid collision with
/// the C++ standard library facility "remove"
2020-03-17 21:33:58 -04:00
void rmove(std::uint_fast8_t const n) noexcept {
if (n <= 32U) {
(m_bits[0] &= ~(static_cast<std::uint32_t>(1) << (n - 1U)));
2016-09-29 19:54:50 -04:00
}
else {
2020-03-17 21:33:58 -04:00
(m_bits[1] &= ~(static_cast<std::uint32_t>(1) << (n - 33U)));
2012-08-14 18:00:48 -04:00
}
}
2014-04-13 21:35:34 -04:00
//! find the maximum element in the set, returns zero if the set is empty
2020-03-17 21:33:58 -04:00
std::uint_fast8_t findMax(void) const noexcept {
return (m_bits[1] != 0U)
? (QF_LOG2(m_bits[1]) + 32U)
2016-09-29 19:54:50 -04:00
: (QF_LOG2(m_bits[0]));
2012-08-14 18:00:48 -04:00
}
};
2016-09-29 19:54:50 -04:00
#endif // QF_MAX_ACTIVE
2014-04-13 21:35:34 -04:00
} // namespace QP
2012-08-14 18:00:48 -04:00
2019-10-27 12:26:31 -04:00
#endif // QPSET_HPP
2012-08-14 18:00:48 -04:00