| /* |
| * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #ifndef LOGGING_RTC_EVENT_LOG_RTC_EVENT_PROCESSOR_H_ |
| #define LOGGING_RTC_EVENT_LOG_RTC_EVENT_PROCESSOR_H_ |
| |
| #include <stdint.h> |
| #include <algorithm> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "rtc_base/checks.h" |
| #include "rtc_base/function_view.h" |
| |
| namespace webrtc { |
| |
| // This file contains helper class used to process the elements of two or more |
| // sorted lists in timestamp order. The effect is the same as doing a merge step |
| // in the merge-sort algorithm but without copying the elements or modifying the |
| // lists. |
| |
| // Interface to allow "merging" lists of different types. ProcessNext() |
| // processes the next unprocesses element in the list. IsEmpty() checks if all |
| // elements have been processed. GetNextTime returns the timestamp of the next |
| // unprocessed element. |
| class ProcessableEventListInterface { |
| public: |
| virtual ~ProcessableEventListInterface() = default; |
| virtual void ProcessNext() = 0; |
| virtual bool IsEmpty() const = 0; |
| virtual int64_t GetNextTime() const = 0; |
| }; |
| |
| // ProcessableEventList encapsulates a list of events and a function that will |
| // be applied to each element of the list. |
| template <typename T> |
| class ProcessableEventList : public ProcessableEventListInterface { |
| public: |
| // N.B. |f| is not owned by ProcessableEventList. The caller must ensure that |
| // the function object or lambda outlives ProcessableEventList and |
| // RtcEventProcessor. The same thing applies to the iterators (begin, end); |
| // the vector must outlive ProcessableEventList and must not be modified until |
| // processing has finished. |
| ProcessableEventList(typename std::vector<T>::const_iterator begin, |
| typename std::vector<T>::const_iterator end, |
| rtc::FunctionView<void(const T&)> f) |
| : begin_(begin), end_(end), f_(f) {} |
| |
| void ProcessNext() override { |
| RTC_DCHECK(!IsEmpty()); |
| f_(*begin_); |
| ++begin_; |
| } |
| |
| bool IsEmpty() const override { return begin_ == end_; } |
| |
| int64_t GetNextTime() const override { |
| RTC_DCHECK(!IsEmpty()); |
| return begin_->log_time_us(); |
| } |
| |
| private: |
| typename std::vector<T>::const_iterator begin_; |
| typename std::vector<T>::const_iterator end_; |
| rtc::FunctionView<void(const T&)> f_; |
| }; |
| |
| // Helper class used to "merge" two or more lists of ordered RtcEventLog events |
| // so that they can be treated as a single ordered list. Since the individual |
| // lists may have different types, we need to access the lists via pointers to |
| // the common base class. |
| // |
| // Usage example: |
| // ParsedRtcEventLogNew log; |
| // auto incoming_handler = [] (LoggedRtcpPacketIncoming elem) { ... }; |
| // auto incoming_rtcp = |
| // absl::make_unique<ProcessableEventList<LoggedRtcpPacketIncoming>>( |
| // log.incoming_rtcp_packets().begin(), |
| // log.incoming_rtcp_packets().end(), |
| // incoming_handler); |
| // auto outgoing_handler = [] (LoggedRtcpPacketOutgoing elem) { ... }; |
| // auto outgoing_rtcp = |
| // absl::make_unique<ProcessableEventList<LoggedRtcpPacketOutgoing>>( |
| // log.outgoing_rtcp_packets().begin(), |
| // log.outgoing_rtcp_packets().end(), |
| // outgoing_handler); |
| // |
| // RtcEventProcessor processor; |
| // processor.AddEvents(std::move(incoming_rtcp)); |
| // processor.AddEvents(std::move(outgoing_rtcp)); |
| // processor.ProcessEventsInOrder(); |
| class RtcEventProcessor { |
| public: |
| // The elements of each list is processed in the index order. To process all |
| // elements in all lists in timestamp order, each lists need to be sorted in |
| // timestamp order prior to insertion. Otherwise, |
| void AddEvents(std::unique_ptr<ProcessableEventListInterface> events) { |
| if (!events->IsEmpty()) { |
| event_lists_.push_back(std::move(events)); |
| std::push_heap(event_lists_.begin(), event_lists_.end(), Cmp); |
| } |
| } |
| |
| void ProcessEventsInOrder() { |
| // |event_lists_| is a min-heap of lists ordered by the timestamp of the |
| // first element in the list. We therefore process the first element of the |
| // first list, then reinsert the remainder of that list into the heap |
| // if the list still contains unprocessed elements. |
| while (!event_lists_.empty()) { |
| event_lists_.front()->ProcessNext(); |
| std::pop_heap(event_lists_.begin(), event_lists_.end(), Cmp); |
| if (event_lists_.back()->IsEmpty()) { |
| event_lists_.pop_back(); |
| } else { |
| std::push_heap(event_lists_.begin(), event_lists_.end(), Cmp); |
| } |
| } |
| } |
| |
| private: |
| using ListPtrType = std::unique_ptr<ProcessableEventListInterface>; |
| std::vector<ListPtrType> event_lists_; |
| // Comparison function to make |event_lists_| into a min heap. |
| static bool Cmp(const ListPtrType& a, const ListPtrType& b) { |
| return a->GetNextTime() > b->GetNextTime(); |
| } |
| }; |
| |
| } // namespace webrtc |
| |
| #endif // LOGGING_RTC_EVENT_LOG_RTC_EVENT_PROCESSOR_H_ |