kranewm

An ICCCM & EWMH compliant X11 reparenting, dynamic window manager, written in C++
git clone git://git.deurzen.net/kranewm
Log | Files | Refs | LICENSE

cycle.t.hh (12540B)


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