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__