blob: 9eee4815f263481af719f74e26f90e2c53d36811 [file] [log] [blame]
/*
* 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_