GenericTypes.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. * Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "GenericTypes.h"
  7. #include <AK/BinarySearch.h>
  8. #include <AK/Error.h>
  9. #include <AK/Optional.h>
  10. namespace Audio {
  11. size_t SeekTable::size() const
  12. {
  13. return m_seek_points.size();
  14. }
  15. ReadonlySpan<SeekPoint> SeekTable::seek_points() const
  16. {
  17. return m_seek_points.span();
  18. }
  19. Optional<SeekPoint const&> SeekTable::seek_point_before(u64 sample_index) const
  20. {
  21. if (m_seek_points.is_empty())
  22. return {};
  23. size_t nearby_seek_point_index = 0;
  24. AK::binary_search(m_seek_points, sample_index, &nearby_seek_point_index, [](auto const& sample_index, auto const& seekpoint_candidate) {
  25. // Subtraction with i64 cast may cause overflow.
  26. if (sample_index > seekpoint_candidate.sample_index)
  27. return 1;
  28. if (sample_index == seekpoint_candidate.sample_index)
  29. return 0;
  30. return -1;
  31. });
  32. // Binary search will always give us a close index, but it may be too large or too small.
  33. // By doing the index adjustment in this order, we will always find a seek point before the given sample.
  34. while (nearby_seek_point_index < m_seek_points.size() - 1 && m_seek_points[nearby_seek_point_index].sample_index < sample_index)
  35. ++nearby_seek_point_index;
  36. while (nearby_seek_point_index > 0 && m_seek_points[nearby_seek_point_index].sample_index > sample_index)
  37. --nearby_seek_point_index;
  38. if (m_seek_points[nearby_seek_point_index].sample_index > sample_index)
  39. return {};
  40. return m_seek_points[nearby_seek_point_index];
  41. }
  42. Optional<u64> SeekTable::seek_point_sample_distance_around(u64 sample_index) const
  43. {
  44. if (m_seek_points.is_empty())
  45. return {};
  46. size_t nearby_seek_point_index = 0;
  47. AK::binary_search(m_seek_points, sample_index, &nearby_seek_point_index, [](auto const& sample_index, auto const& seekpoint_candidate) {
  48. // Subtraction with i64 cast may cause overflow.
  49. if (sample_index > seekpoint_candidate.sample_index)
  50. return 1;
  51. if (sample_index == seekpoint_candidate.sample_index)
  52. return 0;
  53. return -1;
  54. });
  55. while (nearby_seek_point_index < m_seek_points.size() && m_seek_points[nearby_seek_point_index].sample_index <= sample_index)
  56. ++nearby_seek_point_index;
  57. // There is no seek point beyond the sample index.
  58. if (nearby_seek_point_index >= m_seek_points.size())
  59. return {};
  60. auto upper_seek_point_index = nearby_seek_point_index;
  61. while (nearby_seek_point_index > 0 && m_seek_points[nearby_seek_point_index].sample_index > sample_index)
  62. --nearby_seek_point_index;
  63. auto lower_seek_point_index = nearby_seek_point_index;
  64. VERIFY(upper_seek_point_index >= lower_seek_point_index);
  65. return m_seek_points[upper_seek_point_index].sample_index - m_seek_points[lower_seek_point_index].sample_index;
  66. }
  67. ErrorOr<void> SeekTable::insert_seek_point(SeekPoint seek_point)
  68. {
  69. if (auto previous_seek_point = seek_point_before(seek_point.sample_index); previous_seek_point.has_value() && previous_seek_point->sample_index == seek_point.sample_index) {
  70. // Do not insert a duplicate seek point.
  71. return {};
  72. }
  73. // FIXME: This could be even faster if we used binary search while finding the insertion point.
  74. return m_seek_points.try_insert_before_matching(seek_point, [&](auto const& other_seek_point) {
  75. return seek_point.sample_index < other_seek_point.sample_index;
  76. });
  77. }
  78. }