A C++ toolbox repo until the pair uTL/dTL arives
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

266 lines
9.9 KiB

  1. /*!
  2. * \file cont/edeque.h
  3. * \brief
  4. * A deque with event based callables
  5. *
  6. * \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net>
  7. *
  8. * <dl class=\"section copyright\"><dt>License</dt><dd>
  9. * The MIT License (MIT)
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in all
  19. * copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  27. * SOFTWARE.
  28. * </dd></dl>
  29. */
  30. #ifndef TBX_CONT_EDEQUE_H_
  31. #define TBX_CONT_EDEQUE_H_
  32. #include <core/core.h>
  33. #include <cont/deque.h>
  34. #include <functional>
  35. #include <utility>
  36. #include <type_traits>
  37. namespace tbx {
  38. /*!
  39. * \class edeque
  40. * \brief
  41. * A statically allocated deque with size and data matching event based callables.
  42. *
  43. * The edeque inherits deque and provide the callable functionality as a wrapper.
  44. *
  45. * There are two types of events.
  46. * - Size based events, which are cleared as soon as they served. These events are checked
  47. * every time the deque change its size. If the criteria match we call the callable of type
  48. * \c Fn
  49. * - Data based events, which are permanently. These events are checked every time an item is
  50. * pushed or popped from the deque. If the criteria match we call call the callable of type
  51. * \c Fn
  52. *
  53. * \tparam Data_t The char-like queued item type. Usually \c char
  54. * \tparam N The size of edeque
  55. * \tparam Fn The type of Callable
  56. */
  57. template <typename Data_t, size_t N, typename Fn = std::function<void()>>
  58. class edeque : public deque<Data_t, N> {
  59. public:
  60. // meta-identity types
  61. using type = edeque<Data_t, N>;
  62. using base_type = deque<Data_t, N>;
  63. using callable_t = Fn;
  64. // STL
  65. using value_type = typename base_type::value_type;
  66. using reference = typename base_type::reference;
  67. using const_reference = typename base_type::const_reference;
  68. using pointer = typename base_type::pointer;
  69. using const_pointer = typename base_type::const_pointer;
  70. using iterator = typename base_type::iterator;
  71. using const_iterator = typename base_type::const_iterator;
  72. using reverse_iterator = typename base_type::reverse_iterator;
  73. using const_reverse_iterator= typename base_type::const_reverse_iterator;
  74. //! \name Public types
  75. //! @{
  76. public:
  77. //! \enum match_mode
  78. //! The mode of match operation
  79. enum class match_mode { SIZE, DATA };
  80. //! \enum size_match
  81. //! The type of matching for size based match
  82. enum class size_match { DISABLED =0, EQ, NE, LT, LE, GT, GE };
  83. //! \enum data_match
  84. //! The type of matching for data based match
  85. enum class data_match { DISABLED =0, MATCH, MISMATCH};
  86. //! \struct size_trigger
  87. //! Size trigger data type
  88. struct size_trigger {
  89. size_match type;
  90. size_t size;
  91. };
  92. //! \struct data_trigger
  93. //! Data trigger data type
  94. struct data_trigger {
  95. data_match type;
  96. Data_t value;
  97. };
  98. //! \union trigger
  99. //! \brief
  100. //! A union for the common types.
  101. //! There is only one mode. Either "size" with \ref size_match type and a size to match,
  102. //! or "data" with \ref data_match type and a value to match
  103. union trigger {
  104. size_trigger tsize;
  105. data_trigger tdata;
  106. };
  107. //! @}
  108. //! \name Constructor / Destructor
  109. //! @{
  110. public:
  111. //! Default constructor
  112. constexpr edeque () noexcept :
  113. base_type() { }
  114. //!
  115. constexpr edeque (size_match match, size_t size, callable_t&& fn) :
  116. base_type(),
  117. mode_{match_mode::SIZE},
  118. callback_{std::forward<callable_t>(fn)} {
  119. trigger_.tsize.type = match;
  120. trigger_.tsize.size = size;
  121. }
  122. constexpr edeque (data_match match, Data_t value, callable_t&& fn) :
  123. base_type(),
  124. mode_{match_mode::DATA},
  125. callback_{std::forward<callable_t>(fn)} {
  126. trigger_.tdata.type = match;
  127. trigger_.tdata.value = value;
  128. }
  129. //! @}
  130. //! \name Public interface
  131. //! @{
  132. //! \brief
  133. //! Manually checks the size trigger and calls it we have match.
  134. //! \return True if the callable has called.
  135. bool check_trigger () {
  136. return check_trigger_size_();
  137. }
  138. //! \brief
  139. //! Manually set (or alters) the \c size trigger. This function does not fire the
  140. //! \ref check_trigger()
  141. //! \param match The match type
  142. //! \param size The size for with we check against
  143. //! \param fn The callable to call on match
  144. void set_trigger (size_match match, size_t size, callable_t&& fn) {
  145. mode_ = match_mode::SIZE;
  146. trigger_.tsize.type = match;
  147. trigger_.tsize.size = size;
  148. callback_ = std::forward<callable_t>(fn);
  149. }
  150. //! \brief
  151. //! Manually set (or alters) the \c data trigger. This function does not fire the
  152. //! \ref check_trigger()
  153. //! \param match The match type
  154. //! \param value The value for with we check against
  155. //! \param fn The callable to call on match
  156. void set_trigger (data_match match, Data_t value, callable_t&& fn) {
  157. mode_ = match_mode::DATA;
  158. trigger_.tdata.type = match;
  159. trigger_.tdata.value= value;
  160. callback_ = std::forward<callable_t>(fn);
  161. }
  162. //! \brief Manually clears the trigger
  163. void clear_trigger () {
  164. mode_ = match_mode{};
  165. trigger_ = trigger{};
  166. callback_ = callable_t{};
  167. }
  168. //! @}
  169. //! \name Base class overwrites
  170. //! @{
  171. void push_front (const Data_t& it) {
  172. base_type::push_front(it);
  173. check_trigger_async_(it);
  174. }
  175. Data_t pop_front () {
  176. Data_t t = base_type::pop_front();
  177. check_trigger_async_(t);
  178. return t;
  179. }
  180. void push_back (const Data_t& it) {
  181. base_type::push_back(it);
  182. check_trigger_async_(it);
  183. }
  184. Data_t pop_back () {
  185. Data_t t = base_type::pop_back();
  186. check_trigger_async_(t);
  187. return t;
  188. }
  189. //! @}
  190. //! \name Public interface
  191. //! @{
  192. private:
  193. //! \brief
  194. //! Manually checks the size trigger and calls it we have match.
  195. //! \return True if the callable has called.
  196. bool check_trigger_size_ () {
  197. bool match;
  198. switch (trigger_.tsize.type) {
  199. default:
  200. case size_match::DISABLED: match = false; break;
  201. case size_match::EQ: match = (base_type::size() == trigger_.tsize.size); break;
  202. case size_match::NE: match = (base_type::size() != trigger_.tsize.size); break;
  203. case size_match::LT: match = (base_type::size() < trigger_.tsize.size); break;
  204. case size_match::LE: match = (base_type::size() <= trigger_.tsize.size); break;
  205. case size_match::GT: match = (base_type::size() > trigger_.tsize.size); break;
  206. case size_match::GE: match = (base_type::size() >= trigger_.tsize.size); break;
  207. }
  208. if (match) {
  209. callback_();
  210. clear_trigger();
  211. }
  212. return match;
  213. }
  214. //! \brief
  215. //! Manually checks the data trigger and calls it we have match.
  216. //! \param it The item to check against
  217. //! \return True if the callable has called.
  218. bool check_trigger_value_ (const Data_t& it) {
  219. bool match;
  220. switch (trigger_.tdata.type) {
  221. default:
  222. case data_match::DISABLED: match = false; break;
  223. case data_match::MATCH: match = (it == trigger_.tdata.value); break;
  224. case data_match::MISMATCH: match = (it != trigger_.tdata.value); break;
  225. }
  226. if (match)
  227. callback_();
  228. return match;
  229. }
  230. //! Wrapper for both triggers
  231. bool check_trigger_async_ (const Data_t& it) {
  232. switch (mode_) {
  233. default:
  234. case match_mode::SIZE: return check_trigger_size_();
  235. case match_mode::DATA: return check_trigger_value_(it);
  236. }
  237. }
  238. //! @}
  239. private:
  240. match_mode mode_{};
  241. trigger trigger_{};
  242. callable_t callback_{};
  243. };
  244. }
  245. #endif /* TBX_CONT_EDEQUE_H_ */