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 }