зеркало из https://github.com/mozilla/gecko-dev.git
501 строка
21 KiB
C++
501 строка
21 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef ProgressLogger_h
|
|
#define ProgressLogger_h
|
|
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/ProportionValue.h"
|
|
#include "mozilla/RefCounted.h"
|
|
#include "mozilla/RefPtr.h"
|
|
|
|
#include <atomic>
|
|
|
|
// Uncomment to printf ProcessLogger updates.
|
|
// #define DEBUG_PROCESSLOGGER
|
|
|
|
#ifdef DEBUG_PROCESSLOGGER
|
|
# include "mozilla/BaseProfilerUtils.h"
|
|
# include <cstdio>
|
|
#endif // DEBUG_PROCESSLOGGER
|
|
|
|
namespace mozilla {
|
|
|
|
// A `ProgressLogger` is used to update a referenced atomic `ProportionValue`,
|
|
// and can recursively create a sub-logger corresponding to a subset of their
|
|
// own range, but that sub-logger's updates are done in its local 0%-100% range.
|
|
// The typical usage is for multi-level tasks, where each level can estimate its
|
|
// own work and the work delegated to a next-level function, without knowing how
|
|
// this local work relates to the higher-level total work. See
|
|
// `CreateSubLoggerFromTo` for details.
|
|
// Note that this implementation is single-threaded, it does not support logging
|
|
// progress from multiple threads at the same time.
|
|
class ProgressLogger {
|
|
public:
|
|
// An RefPtr'd object of this class is used as the target of all
|
|
// ProgressLogger updates, and it may be shared to make these updates visible
|
|
// from other code in any thread.
|
|
class SharedProgress : public external::AtomicRefCounted<SharedProgress> {
|
|
public:
|
|
MOZ_DECLARE_REFCOUNTED_TYPENAME(SharedProgress)
|
|
|
|
SharedProgress() = default;
|
|
|
|
SharedProgress(const SharedProgress&) = delete;
|
|
SharedProgress& operator=(const SharedProgress&) = delete;
|
|
|
|
// This constant is used to indicate that an update may change the progress
|
|
// value, but should not modify the previously-recorded location.
|
|
static constexpr const char* NO_LOCATION_UPDATE = nullptr;
|
|
|
|
// Set the current progress and location, but the previous location is not
|
|
// overwritten if the new one is null or empty.
|
|
// The location and then the progress are atomically "released", so that all
|
|
// preceding writes on this thread will be visible to other threads reading
|
|
// these values; most importantly when reaching 100% progress, the reader
|
|
// can be confident that the location is final and the operation being
|
|
// watched has completed.
|
|
void SetProgress(
|
|
ProportionValue aProgress,
|
|
const char* aLocationOrNullEmptyToIgnore = NO_LOCATION_UPDATE) {
|
|
if (aLocationOrNullEmptyToIgnore &&
|
|
*aLocationOrNullEmptyToIgnore != '\0') {
|
|
mLastLocation.store(aLocationOrNullEmptyToIgnore,
|
|
std::memory_order_release);
|
|
}
|
|
mProgress.store(aProgress, std::memory_order_release);
|
|
}
|
|
|
|
// Read the current progress value. Atomically "acquired", so that writes
|
|
// from the thread that stored this value are all visible to the reader
|
|
// here; most importantly when reaching 100%, we can be confident that the
|
|
// location is final and the operation being watched has completed.
|
|
[[nodiscard]] ProportionValue Progress() const {
|
|
return mProgress.load(std::memory_order_acquire);
|
|
}
|
|
|
|
// Read the current progress value. Atomically "acquired".
|
|
[[nodiscard]] const char* LastLocation() const {
|
|
return mLastLocation.load(std::memory_order_acquire);
|
|
}
|
|
|
|
private:
|
|
friend mozilla::detail::RefCounted<SharedProgress,
|
|
mozilla::detail::AtomicRefCount>;
|
|
~SharedProgress() = default;
|
|
|
|
// Progress and last-known location.
|
|
// Beware that these two values are not strongly tied: Reading one then the
|
|
// other may give mismatched information; but it should be fine for
|
|
// informational usage.
|
|
// They are stored using atomic acquire-release ordering, to guarantee that
|
|
// when read, all writes preceding these values are visible.
|
|
std::atomic<ProportionValue> mProgress = ProportionValue{0.0};
|
|
std::atomic<const char*> mLastLocation = nullptr;
|
|
};
|
|
|
|
static constexpr const char* NO_LOCATION_UPDATE =
|
|
SharedProgress::NO_LOCATION_UPDATE;
|
|
|
|
ProgressLogger() = default;
|
|
|
|
// Construct a top-level logger, starting at 0% and expected to end at 100%.
|
|
explicit ProgressLogger(
|
|
RefPtr<SharedProgress> aGlobalProgressOrNull,
|
|
const char* aLocationOrNullEmptyToIgnoreAtStart = NO_LOCATION_UPDATE,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEnd = NO_LOCATION_UPDATE)
|
|
: ProgressLogger{std::move(aGlobalProgressOrNull),
|
|
/* Start */ ProportionValue{0.0},
|
|
/* Multiplier */ ProportionValue{1.0},
|
|
aLocationOrNullEmptyToIgnoreAtStart,
|
|
aLocationOrNullEmptyToIgnoreAtEnd} {}
|
|
|
|
// Don't make copies, it would be confusing!
|
|
// TODO: Copies could one day be allowed to track multi-threaded work, but it
|
|
// is outside the scope of this implementation; Please update if needed.
|
|
ProgressLogger(const ProgressLogger&) = delete;
|
|
ProgressLogger& operator&(const ProgressLogger&) = delete;
|
|
|
|
// Move-construct is allowed, to return from CreateSubLoggerFromTo, and
|
|
// forward straight into a function. Note that moved-from ProgressLoggers must
|
|
// not be used anymore! Use `CreateSubLoggerFromTo` to pass a sub-logger to
|
|
// functions.
|
|
ProgressLogger(ProgressLogger&& aOther)
|
|
: mGlobalProgressOrNull(std::move(aOther.mGlobalProgressOrNull)),
|
|
mLocalStartInGlobalSpace(aOther.mLocalStartInGlobalSpace),
|
|
mLocalToGlobalMultiplier(aOther.mLocalToGlobalMultiplier),
|
|
mLocationAtDestruction(aOther.mLocationAtDestruction) {
|
|
aOther.MarkMovedFrom();
|
|
#ifdef DEBUG_PROCESSLOGGER
|
|
if (mGlobalProgressOrNull) {
|
|
printf("[%d] Moved (staying globally at %.2f in [%.2f, %.2f])\n",
|
|
int(baseprofiler::profiler_current_process_id().ToNumber()),
|
|
GetGlobalProgress().ToDouble() * 100.0,
|
|
mLocalStartInGlobalSpace.ToDouble() * 100.0,
|
|
(mLocalStartInGlobalSpace + mLocalToGlobalMultiplier).ToDouble() *
|
|
100.0);
|
|
}
|
|
#endif // DEBUG_PROCESSLOGGER
|
|
}
|
|
|
|
// Move-assign. This may be useful when starting with a default (empty) logger
|
|
// and later assigning it a progress value to start updating.
|
|
ProgressLogger& operator=(ProgressLogger&& aOther) {
|
|
mGlobalProgressOrNull = std::move(aOther.mGlobalProgressOrNull);
|
|
mLocalStartInGlobalSpace = aOther.mLocalStartInGlobalSpace;
|
|
mLocalToGlobalMultiplier = aOther.mLocalToGlobalMultiplier;
|
|
mLocationAtDestruction = aOther.mLocationAtDestruction;
|
|
aOther.MarkMovedFrom();
|
|
#ifdef DEBUG_PROCESSLOGGER
|
|
if (mGlobalProgressOrNull) {
|
|
printf("[%d] Re-assigned (globally at %.2f in [%.2f, %.2f])\n",
|
|
int(baseprofiler::profiler_current_process_id().ToNumber()),
|
|
GetGlobalProgress().ToDouble() * 100.0,
|
|
mLocalStartInGlobalSpace.ToDouble() * 100.0,
|
|
(mLocalStartInGlobalSpace + mLocalToGlobalMultiplier).ToDouble() *
|
|
100.0);
|
|
}
|
|
#endif // DEBUG_PROCESSLOGGER
|
|
return *this;
|
|
}
|
|
|
|
// Destruction sets the local update value to 100% unless empty or moved-from.
|
|
~ProgressLogger() {
|
|
if (!IsMovedFrom()) {
|
|
#ifdef DEBUG_PROCESSLOGGER
|
|
if (mGlobalProgressOrNull) {
|
|
printf("[%d] Destruction:\n",
|
|
int(baseprofiler::profiler_current_process_id().ToNumber()));
|
|
}
|
|
#endif // DEBUG_PROCESSLOGGER
|
|
SetLocalProgress(ProportionValue{1.0}, mLocationAtDestruction);
|
|
}
|
|
}
|
|
|
|
// Retrieve the current progress in the global space. May be invalid.
|
|
[[nodiscard]] ProportionValue GetGlobalProgress() const {
|
|
return mGlobalProgressOrNull ? mGlobalProgressOrNull->Progress()
|
|
: ProportionValue::MakeInvalid();
|
|
}
|
|
|
|
// Retrieve the last known global location. May be null.
|
|
[[nodiscard]] const char* GetLastGlobalLocation() const {
|
|
return mGlobalProgressOrNull ? mGlobalProgressOrNull->LastLocation()
|
|
: nullptr;
|
|
}
|
|
|
|
// Set the current progress in the local space.
|
|
void SetLocalProgress(ProportionValue aLocalProgress,
|
|
const char* aLocationOrNullEmptyToIgnore) {
|
|
MOZ_ASSERT(!IsMovedFrom());
|
|
if (mGlobalProgressOrNull && !mLocalToGlobalMultiplier.IsExactlyZero()) {
|
|
mGlobalProgressOrNull->SetProgress(LocalToGlobal(aLocalProgress),
|
|
aLocationOrNullEmptyToIgnore);
|
|
#ifdef DEBUG_PROCESSLOGGER
|
|
printf("[%d] - local %.0f%% ~ global %.2f%% \"%s\"\n",
|
|
int(baseprofiler::profiler_current_process_id().ToNumber()),
|
|
aLocalProgress.ToDouble() * 100.0,
|
|
LocalToGlobal(aLocalProgress).ToDouble() * 100.0,
|
|
aLocationOrNullEmptyToIgnore ? aLocationOrNullEmptyToIgnore
|
|
: "<null>");
|
|
#endif // DEBUG_PROCESSLOGGER
|
|
}
|
|
}
|
|
|
|
// Create a sub-logger that will record progress in the given local range.
|
|
// E.g.: `f(pl.CreateSubLoggerFromTo(0.2, "f...", 0.4, "f done"));` expects
|
|
// that `f` will produce work in the local range 0.2 (when starting) to 0.4
|
|
// (when returning); `f` itself will update this provided logger from 0.0
|
|
// to 1.0 (local to that `f` function), which will effectively be converted to
|
|
// 0.2-0.4 (local to the calling function).
|
|
// This can cascade multiple levels, each deeper level affecting a smaller and
|
|
// smaller range in the global output.
|
|
[[nodiscard]] ProgressLogger CreateSubLoggerFromTo(
|
|
ProportionValue aSubStartInLocalSpace,
|
|
const char* aLocationOrNullEmptyToIgnoreAtStart,
|
|
ProportionValue aSubEndInLocalSpace,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEnd = NO_LOCATION_UPDATE) {
|
|
MOZ_ASSERT(!IsMovedFrom());
|
|
if (!mGlobalProgressOrNull) {
|
|
return ProgressLogger{};
|
|
}
|
|
const ProportionValue subStartInGlobalSpace =
|
|
LocalToGlobal(aSubStartInLocalSpace);
|
|
const ProportionValue subEndInGlobalSpace =
|
|
LocalToGlobal(aSubEndInLocalSpace);
|
|
if (subStartInGlobalSpace.IsInvalid() || subEndInGlobalSpace.IsInvalid()) {
|
|
return ProgressLogger{mGlobalProgressOrNull,
|
|
/* Start */ ProportionValue::MakeInvalid(),
|
|
/* Multiplier */ ProportionValue{0.0},
|
|
aLocationOrNullEmptyToIgnoreAtStart,
|
|
aLocationOrNullEmptyToIgnoreAtEnd};
|
|
}
|
|
#ifdef DEBUG_PROCESSLOGGER
|
|
if (mGlobalProgressOrNull) {
|
|
printf("[%d] * Sub: local [%.0f%%, %.0f%%] ~ global [%.2f%%, %.2f%%]\n",
|
|
int(baseprofiler::profiler_current_process_id().ToNumber()),
|
|
aSubStartInLocalSpace.ToDouble() * 100.0,
|
|
aSubEndInLocalSpace.ToDouble() * 100.0,
|
|
subStartInGlobalSpace.ToDouble() * 100.0,
|
|
subEndInGlobalSpace.ToDouble() * 100.0);
|
|
}
|
|
#endif // DEBUG_PROCESSLOGGER
|
|
return ProgressLogger{
|
|
mGlobalProgressOrNull,
|
|
/* Start */ subStartInGlobalSpace,
|
|
/* Multipler */ subEndInGlobalSpace - subStartInGlobalSpace,
|
|
aLocationOrNullEmptyToIgnoreAtStart, aLocationOrNullEmptyToIgnoreAtEnd};
|
|
}
|
|
|
|
// Helper with no start location.
|
|
[[nodiscard]] ProgressLogger CreateSubLoggerFromTo(
|
|
ProportionValue aSubStartInLocalSpace,
|
|
ProportionValue aSubEndInLocalSpace,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEnd = NO_LOCATION_UPDATE) {
|
|
return CreateSubLoggerFromTo(aSubStartInLocalSpace, NO_LOCATION_UPDATE,
|
|
aSubEndInLocalSpace,
|
|
aLocationOrNullEmptyToIgnoreAtEnd);
|
|
}
|
|
|
|
// Helper using the current progress as start.
|
|
[[nodiscard]] ProgressLogger CreateSubLoggerTo(
|
|
const char* aLocationOrNullEmptyToIgnoreAtStart,
|
|
ProportionValue aSubEndInLocalSpace,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEnd = NO_LOCATION_UPDATE) {
|
|
MOZ_ASSERT(!IsMovedFrom());
|
|
if (!mGlobalProgressOrNull) {
|
|
return ProgressLogger{};
|
|
}
|
|
const ProportionValue subStartInGlobalSpace = GetGlobalProgress();
|
|
const ProportionValue subEndInGlobalSpace =
|
|
LocalToGlobal(aSubEndInLocalSpace);
|
|
if (subStartInGlobalSpace.IsInvalid() || subEndInGlobalSpace.IsInvalid()) {
|
|
return ProgressLogger{mGlobalProgressOrNull,
|
|
/* Start */ ProportionValue::MakeInvalid(),
|
|
/* Multiplier */ ProportionValue{0.0},
|
|
aLocationOrNullEmptyToIgnoreAtStart,
|
|
aLocationOrNullEmptyToIgnoreAtEnd};
|
|
}
|
|
#ifdef DEBUG_PROCESSLOGGER
|
|
if (mGlobalProgressOrNull) {
|
|
printf("[%d] * Sub: local [(here), %.0f%%] ~ global [%.2f%%, %.2f%%]\n",
|
|
int(baseprofiler::profiler_current_process_id().ToNumber()),
|
|
aSubEndInLocalSpace.ToDouble() * 100.0,
|
|
subStartInGlobalSpace.ToDouble() * 100.0,
|
|
subEndInGlobalSpace.ToDouble() * 100.0);
|
|
}
|
|
#endif // DEBUG_PROCESSLOGGER
|
|
return ProgressLogger{
|
|
mGlobalProgressOrNull,
|
|
/* Start */ subStartInGlobalSpace,
|
|
/* Multiplier */ subEndInGlobalSpace - subStartInGlobalSpace,
|
|
aLocationOrNullEmptyToIgnoreAtStart, aLocationOrNullEmptyToIgnoreAtEnd};
|
|
}
|
|
|
|
// Helper using the current progress as start, no start location.
|
|
[[nodiscard]] ProgressLogger CreateSubLoggerTo(
|
|
ProportionValue aSubEndInLocalSpace,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEnd = NO_LOCATION_UPDATE) {
|
|
return CreateSubLoggerTo(NO_LOCATION_UPDATE, aSubEndInLocalSpace,
|
|
aLocationOrNullEmptyToIgnoreAtEnd);
|
|
}
|
|
|
|
class IndexAndProgressLoggerRange;
|
|
|
|
[[nodiscard]] inline IndexAndProgressLoggerRange CreateLoopSubLoggersFromTo(
|
|
ProportionValue aLoopStartInLocalSpace,
|
|
ProportionValue aLoopEndInLocalSpace, uint32_t aLoopCount,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEdges =
|
|
ProgressLogger::NO_LOCATION_UPDATE);
|
|
[[nodiscard]] inline IndexAndProgressLoggerRange CreateLoopSubLoggersTo(
|
|
ProportionValue aLoopEndInLocalSpace, uint32_t aLoopCount,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEdges =
|
|
ProgressLogger::NO_LOCATION_UPDATE);
|
|
|
|
private:
|
|
// All constructions start at the local 0%.
|
|
ProgressLogger(RefPtr<SharedProgress> aGlobalProgressOrNull,
|
|
ProportionValue aLocalStartInGlobalSpace,
|
|
ProportionValue aLocalToGlobalMultiplier,
|
|
const char* aLocationOrNullEmptyToIgnoreAtConstruction,
|
|
const char* aLocationOrNullEmptyToIgnoreAtDestruction)
|
|
: mGlobalProgressOrNull(std::move(aGlobalProgressOrNull)),
|
|
mLocalStartInGlobalSpace(aLocalStartInGlobalSpace),
|
|
mLocalToGlobalMultiplier(aLocalToGlobalMultiplier),
|
|
mLocationAtDestruction(aLocationOrNullEmptyToIgnoreAtDestruction) {
|
|
MOZ_ASSERT(!IsMovedFrom(), "Don't construct a moved-from object!");
|
|
SetLocalProgress(ProportionValue{0.0},
|
|
aLocationOrNullEmptyToIgnoreAtConstruction);
|
|
}
|
|
|
|
void MarkMovedFrom() {
|
|
mLocalToGlobalMultiplier = ProportionValue::MakeInvalid();
|
|
}
|
|
[[nodiscard]] bool IsMovedFrom() const {
|
|
return mLocalToGlobalMultiplier.IsInvalid();
|
|
}
|
|
|
|
[[nodiscard]] ProportionValue LocalToGlobal(
|
|
ProportionValue aLocalProgress) const {
|
|
return aLocalProgress * mLocalToGlobalMultiplier + mLocalStartInGlobalSpace;
|
|
}
|
|
|
|
// Global progress value to update from local changes.
|
|
RefPtr<SharedProgress> mGlobalProgressOrNull;
|
|
|
|
// How much to multiply and add to a local [0, 100%] value, to get the
|
|
// corresponding value in the global space.
|
|
// If mLocalToGlobalMultiplier is invalid, this ProgressLogger is moved-from,
|
|
// functions should not be used, and destructor won't update progress.
|
|
ProportionValue mLocalStartInGlobalSpace;
|
|
ProportionValue mLocalToGlobalMultiplier;
|
|
|
|
const char* mLocationAtDestruction = nullptr;
|
|
};
|
|
|
|
// Helper class for range-for loop, e.g., with `aProgressLogger`:
|
|
// for (auto [index, loopProgressLogger] :
|
|
// IndexAndProgressLoggerRange{aProgressLogger, 30_pc, 50_pc, 10,
|
|
// "looping..."}) {
|
|
// // This will loop 10 times.
|
|
// // `index` is the loop index, from 0 to 9.
|
|
// // The overall loop will start at 30% and end at 50% of aProgressLogger.
|
|
// // `loopProgressLogger` is the progress logger for each iteration,
|
|
// // covering 1/10th of the range, therefore: [30%,32%], then [32%,34%],
|
|
// // etc. until [48%,50%].
|
|
// // Progress is automatically updated before/after each loop.
|
|
// }
|
|
// Note that this implementation is single-threaded, it does not support logging
|
|
// progress from parallel loops.
|
|
class ProgressLogger::IndexAndProgressLoggerRange {
|
|
public:
|
|
struct IndexAndProgressLogger {
|
|
uint32_t index;
|
|
ProgressLogger progressLogger;
|
|
};
|
|
|
|
class IndexAndProgressLoggerEndIterator {
|
|
public:
|
|
explicit IndexAndProgressLoggerEndIterator(uint32_t aIndex)
|
|
: mIndex(aIndex) {}
|
|
|
|
[[nodiscard]] uint32_t Index() const { return mIndex; }
|
|
|
|
private:
|
|
uint32_t mIndex;
|
|
};
|
|
|
|
class IndexAndProgressLoggerIterator {
|
|
public:
|
|
IndexAndProgressLoggerIterator(
|
|
RefPtr<ProgressLogger::SharedProgress> aGlobalProgressOrNull,
|
|
ProportionValue aLoopStartInGlobalSpace,
|
|
ProportionValue aLoopIncrementInGlobalSpace,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEdges)
|
|
: mGlobalProgressOrNull(aGlobalProgressOrNull),
|
|
mLoopStartInGlobalSpace(aLoopStartInGlobalSpace),
|
|
mLoopIncrementInGlobalSpace(aLoopIncrementInGlobalSpace),
|
|
mIndex(0u),
|
|
mLocationOrNullEmptyToIgnoreAtEdges(
|
|
aLocationOrNullEmptyToIgnoreAtEdges) {
|
|
if (mGlobalProgressOrNull) {
|
|
mGlobalProgressOrNull->SetProgress(mLoopStartInGlobalSpace,
|
|
mLocationOrNullEmptyToIgnoreAtEdges);
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] IndexAndProgressLogger operator*() {
|
|
return IndexAndProgressLogger{
|
|
mIndex,
|
|
mGlobalProgressOrNull
|
|
? ProgressLogger{mGlobalProgressOrNull, mLoopStartInGlobalSpace,
|
|
mLoopIncrementInGlobalSpace,
|
|
ProgressLogger::NO_LOCATION_UPDATE,
|
|
ProgressLogger::NO_LOCATION_UPDATE}
|
|
: ProgressLogger{}};
|
|
}
|
|
|
|
[[nodiscard]] bool operator!=(
|
|
const IndexAndProgressLoggerEndIterator& aEnd) const {
|
|
return mIndex != aEnd.Index();
|
|
}
|
|
|
|
IndexAndProgressLoggerIterator& operator++() {
|
|
++mIndex;
|
|
mLoopStartInGlobalSpace =
|
|
mLoopStartInGlobalSpace + mLoopIncrementInGlobalSpace;
|
|
if (mGlobalProgressOrNull) {
|
|
mGlobalProgressOrNull->SetProgress(mLoopStartInGlobalSpace,
|
|
mLocationOrNullEmptyToIgnoreAtEdges);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
RefPtr<ProgressLogger::SharedProgress> mGlobalProgressOrNull;
|
|
ProportionValue mLoopStartInGlobalSpace;
|
|
ProportionValue mLoopIncrementInGlobalSpace;
|
|
uint32_t mIndex;
|
|
const char* mLocationOrNullEmptyToIgnoreAtEdges;
|
|
};
|
|
|
|
[[nodiscard]] IndexAndProgressLoggerIterator begin() {
|
|
return IndexAndProgressLoggerIterator{
|
|
mGlobalProgressOrNull, mLoopStartInGlobalSpace,
|
|
mLoopIncrementInGlobalSpace, mLocationOrNullEmptyToIgnoreAtEdges};
|
|
}
|
|
|
|
[[nodiscard]] IndexAndProgressLoggerEndIterator end() {
|
|
return IndexAndProgressLoggerEndIterator{mLoopCount};
|
|
}
|
|
|
|
private:
|
|
friend class ProgressLogger;
|
|
IndexAndProgressLoggerRange(ProgressLogger& aProgressLogger,
|
|
ProportionValue aLoopStartInGlobalSpace,
|
|
ProportionValue aLoopEndInGlobalSpace,
|
|
uint32_t aLoopCount,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEdges =
|
|
ProgressLogger::NO_LOCATION_UPDATE)
|
|
: mGlobalProgressOrNull(aProgressLogger.mGlobalProgressOrNull),
|
|
mLoopStartInGlobalSpace(aLoopStartInGlobalSpace),
|
|
mLoopIncrementInGlobalSpace(
|
|
(aLoopEndInGlobalSpace - aLoopStartInGlobalSpace) / aLoopCount),
|
|
mLoopCount(aLoopCount),
|
|
mLocationOrNullEmptyToIgnoreAtEdges(
|
|
aLocationOrNullEmptyToIgnoreAtEdges) {}
|
|
|
|
RefPtr<ProgressLogger::SharedProgress> mGlobalProgressOrNull;
|
|
ProportionValue mLoopStartInGlobalSpace;
|
|
ProportionValue mLoopIncrementInGlobalSpace;
|
|
uint32_t mLoopCount;
|
|
const char* mLocationOrNullEmptyToIgnoreAtEdges;
|
|
};
|
|
|
|
[[nodiscard]] ProgressLogger::IndexAndProgressLoggerRange
|
|
ProgressLogger::CreateLoopSubLoggersFromTo(
|
|
ProportionValue aLoopStartInLocalSpace,
|
|
ProportionValue aLoopEndInLocalSpace, uint32_t aLoopCount,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEdges) {
|
|
return IndexAndProgressLoggerRange{
|
|
*this, LocalToGlobal(aLoopStartInLocalSpace),
|
|
LocalToGlobal(aLoopEndInLocalSpace), aLoopCount,
|
|
aLocationOrNullEmptyToIgnoreAtEdges};
|
|
}
|
|
|
|
[[nodiscard]] ProgressLogger::IndexAndProgressLoggerRange
|
|
ProgressLogger::CreateLoopSubLoggersTo(
|
|
ProportionValue aLoopEndInLocalSpace, uint32_t aLoopCount,
|
|
const char* aLocationOrNullEmptyToIgnoreAtEdges) {
|
|
return IndexAndProgressLoggerRange{
|
|
*this, GetGlobalProgress(), LocalToGlobal(aLoopEndInLocalSpace),
|
|
aLoopCount, aLocationOrNullEmptyToIgnoreAtEdges};
|
|
}
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif // ProgressLogger_h
|