kranewl

A wlroots-based dynamic Wayland compositor, written in C++, configurable with Lua
git clone git://git.deurzen.net/kranewl
Log | Files | Refs | LICENSE

cycle.t.hh (12572B)


      1 #pragma once
      2 
      3 #include <kranewl/cycle.hh>
      4 #include <kranewl/util.hh>
      5 
      6 template <typename T>
      7 HistoryStack<T>::HistoryStack()
      8     : m_stack({})
      9 {}
     10 
     11 template <typename T>
     12 HistoryStack<T>::~HistoryStack()
     13 {}
     14 
     15 template <typename T>
     16 void
     17 HistoryStack<T>::clear()
     18 {
     19     m_stack.clear();
     20 }
     21 
     22 template <typename T>
     23 void
     24 HistoryStack<T>::push_back(T element)
     25 {
     26     m_stack.push_back(element);
     27 }
     28 
     29 template <typename T>
     30 void
     31 HistoryStack<T>::replace(T element, T replacement)
     32 {
     33     std::optional<Index> index = Util::index_of(m_stack, element);
     34 
     35     if (index)
     36         m_stack[*index] = replacement;
     37 }
     38 
     39 template <typename T>
     40 std::optional<T>
     41 HistoryStack<T>::peek_back() const
     42 {
     43     if (!m_stack.empty())
     44         return m_stack.back();
     45 
     46     return std::nullopt;
     47 }
     48 
     49 template <typename T>
     50 std::optional<T>
     51 HistoryStack<T>::pop_back()
     52 {
     53     if (!m_stack.empty()) {
     54         T element = m_stack.back();
     55         m_stack.pop_back();
     56         return element;
     57     }
     58 
     59     return std::nullopt;
     60 }
     61 
     62 template <typename T>
     63 void
     64 HistoryStack<T>::remove(T element)
     65 {
     66     Util::erase_remove(m_stack, element);
     67 }
     68 
     69 template <typename T>
     70 std::vector<T> const&
     71 HistoryStack<T>::as_vector() const
     72 {
     73     return m_stack;
     74 }
     75 
     76 
     77 template <typename T>
     78 Cycle<T>::Cycle(std::vector<T> elements, bool unwindable)
     79     : m_index(Util::last_index(elements)),
     80       m_elements({}),
     81       m_unwindable(unwindable),
     82       m_stack(HistoryStack<T>())
     83 {
     84     m_elements.resize(elements.size());
     85     std::copy(elements.begin(), elements.end(), m_elements.begin());
     86 }
     87 
     88 template <typename T>
     89 Cycle<T>::Cycle(std::initializer_list<T> elements, bool unwindable)
     90     : m_index(0),
     91       m_elements({}),
     92       m_unwindable(unwindable),
     93       m_stack(HistoryStack<T>())
     94 {
     95     std::copy(elements.begin(), elements.end(), m_elements.begin());
     96     m_index = Util::last_index(m_elements);
     97 }
     98 
     99 template <typename T>
    100 Cycle<T>::~Cycle()
    101 {}
    102 
    103 template <typename T>
    104 bool
    105 Cycle<T>::next_will_wrap(Direction direction) const
    106 {
    107     switch (direction) {
    108     case Direction::Backward: return m_index == 0;
    109     case Direction::Forward: return m_index == Util::last_index(m_elements);
    110     }
    111 
    112     return false;
    113 }
    114 
    115 template <typename T>
    116 bool
    117 Cycle<T>::empty() const
    118 {
    119     return m_elements.empty();
    120 }
    121 
    122 template <typename T>
    123 bool
    124 Cycle<T>::contains(T element) const
    125 {
    126     return Util::contains(m_elements, element);
    127 }
    128 
    129 template <typename T>
    130 bool
    131 Cycle<T>::is_active_element(T element) const
    132 {
    133     std::optional<Index> current = this->index();
    134     return current && *current == index_of_element(element);
    135 }
    136 
    137 template <typename T>
    138 bool
    139 Cycle<T>::is_active_index(Index index) const
    140 {
    141     std::optional<Index> current = this->index();
    142     return current && *current == index;
    143 }
    144 
    145 
    146 template <typename T>
    147 std::size_t
    148 Cycle<T>::size() const
    149 {
    150     return m_elements.size();
    151 }
    152 
    153 template <typename T>
    154 std::size_t
    155 Cycle<T>::length() const
    156 {
    157     return m_elements.size();
    158 }
    159 
    160 
    161 template <typename T>
    162 std::optional<Index>
    163 Cycle<T>::index() const
    164 {
    165     if (m_index < m_elements.size())
    166         return m_index;
    167 
    168     return std::nullopt;
    169 }
    170 
    171 template <typename T>
    172 Index
    173 Cycle<T>::active_index() const
    174 {
    175     return m_index;
    176 }
    177 
    178 template <typename T>
    179 Index
    180 Cycle<T>::last_index() const
    181 {
    182     return Util::last_index(m_elements);
    183 }
    184 
    185 template <typename T>
    186 Index
    187 Cycle<T>::next_index(Direction direction) const
    188 {
    189     return next_index_from(m_index, direction);
    190 }
    191 
    192 template <typename T>
    193 Index
    194 Cycle<T>::next_index_from(Index index, Direction direction) const
    195 {
    196     Index end = Util::last_index(m_elements);
    197 
    198     switch (direction) {
    199     case Direction::Backward: return index == 0 ? end : index - 1;
    200     case Direction::Forward: return index == end ? 0 : index + 1;
    201     default: return index;
    202     }
    203 }
    204 
    205 
    206 template <typename T>
    207 std::optional<Index>
    208 Cycle<T>::index_of_element(const T element) const
    209 {
    210     return Util::index_of(m_elements, element);
    211 }
    212 
    213 
    214 template <typename T>
    215 std::optional<T>
    216 Cycle<T>::next_element(Direction direction) const
    217 {
    218     std::optional<Index> index = next_index(direction);
    219     if (index && *index < m_elements.size())
    220         return m_elements[*index];
    221 
    222     return std::nullopt;
    223 }
    224 
    225 template <typename T>
    226 std::optional<T>
    227 Cycle<T>::active_element() const
    228 {
    229     if (m_index < m_elements.size())
    230         return m_elements[m_index];
    231 
    232     return std::nullopt;
    233 }
    234 
    235 template <typename T>
    236 std::optional<T>
    237 Cycle<T>::prev_active_element() const
    238 {
    239     return m_stack.peek_back();
    240 }
    241 
    242 template <typename T>
    243 std::optional<T>
    244 Cycle<T>::element_at_index(Index index) const
    245 {
    246     if (index < m_elements.size())
    247         return m_elements[index];
    248 
    249     return std::nullopt;
    250 }
    251 
    252 template <typename T>
    253 std::optional<T>
    254 Cycle<T>::element_at_front(T) const
    255 {
    256     if (!m_elements.empty())
    257         return m_elements[0];
    258 
    259     return std::nullopt;
    260 }
    261 
    262 template <typename T>
    263 std::optional<T>
    264 Cycle<T>::element_at_back(T) const
    265 {
    266     if (!m_elements.empty())
    267         return m_elements[Util::last_index(m_elements)];
    268 
    269     return std::nullopt;
    270 }
    271 
    272 
    273 template <typename T>
    274 void
    275 Cycle<T>::activate_first()
    276 {
    277     activate_at_index(0);
    278 }
    279 
    280 template <typename T>
    281 void
    282 Cycle<T>::activate_last()
    283 {
    284     activate_at_index(Util::last_index(m_elements));
    285 }
    286 
    287 template <typename T>
    288 void
    289 Cycle<T>::activate_at_index(Index index)
    290 {
    291     if (index != m_index) {
    292         push_active_to_stack();
    293         m_index = index;
    294     }
    295 }
    296 
    297 template <typename T>
    298 void
    299 Cycle<T>::activate_element(T element)
    300 {
    301     std::optional<Index> index = Util::index_of(m_elements, element);
    302     if (index)
    303         activate_at_index(*index);
    304 }
    305 
    306 
    307 template <typename T>
    308 bool
    309 Cycle<T>::remove_first()
    310 {
    311     bool must_resync = is_active_index(0);
    312 
    313     std::size_t size_before = m_elements.size();
    314     Util::erase_at_index(m_elements, 0);
    315 
    316     if (must_resync)
    317         sync_active();
    318 
    319     return size_before != m_elements.size();
    320 }
    321 
    322 template <typename T>
    323 bool
    324 Cycle<T>::remove_last()
    325 {
    326     Index end = Util::last_index(m_elements);
    327     bool must_resync = is_active_index(end);
    328 
    329     std::size_t size_before = m_elements.size();
    330     Util::erase_at_index(m_elements, end);
    331 
    332     if (must_resync)
    333         sync_active();
    334 
    335     return size_before != m_elements.size();
    336 }
    337 
    338 template <typename T>
    339 bool
    340 Cycle<T>::remove_at_index(Index index)
    341 {
    342     bool must_resync = is_active_index(index);
    343 
    344     std::size_t size_before = m_elements.size();
    345     Util::erase_at_index(m_elements, index);
    346 
    347     if (must_resync)
    348         sync_active();
    349 
    350     return size_before != m_elements.size();
    351 }
    352 
    353 template <typename T>
    354 bool
    355 Cycle<T>::remove_element(T element)
    356 {
    357     std::optional<Index> index = index_of_element(element);
    358     bool must_resync = is_active_element(element);
    359 
    360     std::size_t size_before = m_elements.size();
    361 
    362     Util::erase_remove(m_elements, element);
    363 
    364     m_stack.remove(element);
    365 
    366     if (m_index != 0 && index && m_index >= *index)
    367         --m_index;
    368 
    369     if (must_resync)
    370         sync_active();
    371 
    372     return size_before != m_elements.size();
    373 }
    374 
    375 
    376 template <typename T>
    377 std::optional<T>
    378 Cycle<T>::pop_back()
    379 {
    380     std::optional<T> value = std::nullopt;
    381 
    382     if (!m_elements.empty()) {
    383         bool must_resync = is_active_element(m_elements.back());
    384 
    385         value = std::optional(m_elements.back());
    386         m_elements.pop_back();
    387 
    388         if (must_resync)
    389             sync_active();
    390     }
    391 
    392     return value;
    393 }
    394 
    395 
    396 template <typename T>
    397 void
    398 Cycle<T>::replace_element(T element, T replacement)
    399 {
    400     if (contains(replacement))
    401         return;
    402 
    403     std::optional<Index> index = index_of_element(element);
    404 
    405     if (index) {
    406         m_elements[*index] = replacement;
    407         m_stack.replace(element, replacement);
    408     }
    409 }
    410 
    411 template <typename T>
    412 void
    413 Cycle<T>::swap_elements(T element1, T element2)
    414 {
    415     std::optional<Index> index1 = index_of_element(element1);
    416     std::optional<Index> index2 = index_of_element(element2);
    417 
    418     if (index1 && index2)
    419         std::iter_swap(m_elements.begin() + *index1, m_elements.begin() + *index2);
    420 }
    421 
    422 template <typename T>
    423 void
    424 Cycle<T>::swap_indices(Index index1, Index index2)
    425 {
    426     if (index1 < m_elements.size() && index2 < m_elements.size())
    427         std::iter_swap(m_elements.begin() + index1, m_elements.begin() + index2);
    428 }
    429 
    430 
    431 template <typename T>
    432 void
    433 Cycle<T>::reverse()
    434 {
    435     std::reverse(m_elements.begin(), m_elements.end());
    436 }
    437 
    438 template <typename T>
    439 void
    440 Cycle<T>::rotate(Direction direction)
    441 {
    442     switch (direction) {
    443     case Direction::Backward:
    444     {
    445         std::rotate(
    446             m_elements.rbegin(),
    447             std::next(m_elements.rbegin()),
    448             m_elements.rend()
    449         );
    450 
    451         return;
    452     }
    453     case Direction::Forward:
    454     {
    455         std::rotate(
    456             m_elements.begin(),
    457             std::next(m_elements.begin()),
    458             m_elements.end()
    459         );
    460 
    461         return;
    462     }
    463     default: return;
    464     }
    465 }
    466 
    467 template <typename T>
    468 void
    469 Cycle<T>::rotate_range(Direction direction, Index begin, Index end)
    470 {
    471     if (begin >= end || begin >= m_elements.size() || end > m_elements.size())
    472         return;
    473 
    474     switch (direction) {
    475     case Direction::Backward:
    476     {
    477         std::rotate(
    478             m_elements.begin() + begin,
    479             std::next(m_elements.begin() + begin),
    480             m_elements.begin() + end
    481         );
    482 
    483         return;
    484     }
    485     case Direction::Forward:
    486     {
    487         std::rotate(
    488             m_elements.rend() - end,
    489             std::next(m_elements.rend() - end),
    490             m_elements.rend() - begin
    491         );
    492 
    493         return;
    494     }
    495     default: return;
    496     }
    497 }
    498 
    499 template <typename T>
    500 std::pair<std::optional<T>, std::optional<T>>
    501 Cycle<T>::cycle_active(Direction direction)
    502 {
    503     push_active_to_stack();
    504 
    505     std::optional<T> prev_active = active_element();
    506     m_index = next_index(direction);
    507     std::optional<T> next_active = active_element();
    508 
    509     return std::pair{
    510         prev_active,
    511         next_active
    512     };
    513 }
    514 
    515 template <typename T>
    516 std::pair<std::optional<T>, std::optional<T>>
    517 Cycle<T>::drag_active(Direction direction)
    518 {
    519     Index index = next_index(direction);
    520 
    521     if (m_index != index && m_index < m_elements.size() && index < m_elements.size())
    522         std::iter_swap(m_elements.begin() + m_index, m_elements.begin() + index);
    523 
    524     return cycle_active(direction);
    525 }
    526 
    527 
    528 template <typename T>
    529 void
    530 Cycle<T>::insert_at_front(T element)
    531 {
    532     push_active_to_stack();
    533     m_elements.push_front(element);
    534     m_index = 0;
    535 }
    536 
    537 template <typename T>
    538 void
    539 Cycle<T>::insert_at_back(T element)
    540 {
    541     push_active_to_stack();
    542     m_elements.push_back(element);
    543     m_index = Util::last_index(m_elements);
    544 }
    545 
    546 template <typename T>
    547 void
    548 Cycle<T>::insert_before_index(Index index, T element)
    549 {
    550     if (index >= m_elements.size())
    551         index = Util::last_index(m_elements);
    552 
    553     push_active_to_stack();
    554     m_elements.insert(m_elements.begin() + index, element);
    555 }
    556 
    557 template <typename T>
    558 void
    559 Cycle<T>::insert_after_index(Index index, T element)
    560 {
    561     if (m_elements.empty() || index >= m_elements.size() - 1) {
    562         insert_at_back(element);
    563         return;
    564     }
    565 
    566     push_active_to_stack();
    567     m_elements.insert(m_elements.begin() + index + 1, element);
    568 }
    569 
    570 template <typename T>
    571 void
    572 Cycle<T>::insert_before_element(T other, T element)
    573 {
    574     std::optional<Index> index = index_of_element(other);
    575 
    576     if (index)
    577         insert_before_index(*index, element);
    578     else
    579         insert_at_back(element);
    580 }
    581 
    582 template <typename T>
    583 void
    584 Cycle<T>::insert_after_element(T other, T element)
    585 {
    586     std::optional<Index> index = index_of_element(other);
    587 
    588     if (index)
    589         insert_after_index(*index, element);
    590     else
    591         insert_at_back(element);
    592 }
    593 
    594 
    595 template <typename T>
    596 void
    597 Cycle<T>::clear()
    598 {
    599     m_elements.clear();
    600     m_stack.clear();
    601 }
    602 
    603 
    604 template <typename T>
    605 void
    606 Cycle<T>::sync_active()
    607 {
    608     std::optional<T> element = get_active_from_stack();
    609     for (; element && !contains(*element); element = get_active_from_stack());
    610     if (element)
    611         m_index = *index_of_element(*element);
    612 }
    613 
    614 
    615 template <typename T>
    616 void
    617 Cycle<T>::push_index_to_stack(std::optional<Index> index)
    618 {
    619     if (!m_unwindable || !index)
    620         return;
    621 
    622     std::optional<T> element = element_at_index(*index);
    623     if (element) {
    624         m_stack.remove(*element);
    625         m_stack.push_back(*element);
    626     }
    627 }
    628 
    629 template <typename T>
    630 void
    631 Cycle<T>::push_active_to_stack()
    632 {
    633     if (!m_unwindable)
    634         return;
    635 
    636     push_index_to_stack(index());
    637 }
    638 
    639 template <typename T>
    640 std::optional<T>
    641 Cycle<T>::get_active_from_stack()
    642 {
    643     return m_stack.pop_back();
    644 }
    645 
    646 
    647 template <typename T>
    648 std::deque<T> const&
    649 Cycle<T>::as_deque() const
    650 {
    651     return m_elements;
    652 }
    653 
    654 template <typename T>
    655 std::vector<T> const&
    656 Cycle<T>::stack() const
    657 {
    658     return m_stack.as_vector();
    659 }