Initially refactored statistics module to simplify value types changing.

This commit is contained in:
23rd 2024-04-11 17:37:54 +03:00 committed by John Preston
parent 7ffa9844e2
commit a37cbd7d05
14 changed files with 97 additions and 71 deletions

View File

@ -30,14 +30,15 @@ struct StatisticalChart {
[[nodiscard]] int findIndex(int left, int right, float64 v) const;
struct Line final {
std::vector<int> y;
std::vector<Statistic::ChartValue> y;
Statistic::SegmentTree segmentTree;
int id = 0;
QString idString;
QString name;
int maxValue = 0;
int minValue = std::numeric_limits<int>::max();
Statistic::ChartValue maxValue = 0;
Statistic::ChartValue minValue =
std::numeric_limits<Statistic::ChartValue>::max();
QString colorKey;
QColor color;
QColor colorDark;
@ -55,8 +56,9 @@ struct StatisticalChart {
float64 max = 0.;
} defaultZoomXIndex;
int maxValue = 0;
int minValue = std::numeric_limits<int>::max();
Statistic::ChartValue maxValue = 0;
Statistic::ChartValue minValue =
std::numeric_limits<Statistic::ChartValue>::max();
float64 oneDayPercentage = 0.;

View File

@ -12,17 +12,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Statistic {
namespace {
constexpr auto kMinLines = int(2);
constexpr auto kMaxLines = int(6);
constexpr auto kMinLines = ChartValue(2);
constexpr auto kMaxLines = ChartValue(6);
constexpr auto kStep = 5.;
[[nodiscard]] int Round(int maxValue) {
const auto k = int(maxValue / kStep);
[[nodiscard]] ChartValue Round(ChartValue maxValue) {
const auto k = ChartValue(maxValue / kStep);
return (k % 10 == 0) ? maxValue : ((maxValue / 10 + 1) * 10);
}
[[nodiscard]] QString Format(int absoluteValue) {
constexpr auto kTooMuch = int(10'000);
[[nodiscard]] QString Format(ChartValue absoluteValue) {
constexpr auto kTooMuch = ChartValue(10'000);
return (absoluteValue >= kTooMuch)
? Lang::FormatCountToShort(absoluteValue).string
: QString::number(absoluteValue);
@ -31,8 +31,8 @@ constexpr auto kStep = 5.;
} // namespace
ChartRulersData::ChartRulersData(
int newMaxHeight,
int newMinHeight,
ChartValue newMaxHeight,
ChartValue newMinHeight,
bool useMinHeight,
float64 rightRatio,
Fn<QString(float64)> leftCustomCaption,
@ -42,11 +42,13 @@ ChartRulersData::ChartRulersData(
? Round(newMaxHeight)
: newMaxHeight;
const auto step = std::max(1, int(std::ceil(v / kStep)));
const auto step = std::max(
ChartValue(1),
ChartValue(std::ceil(v / kStep)));
auto n = kMaxLines;
if (v < kMaxLines) {
n = std::max(2, v + 1);
n = std::max(2, int(v + 1));
} else if (v / 2 < kMaxLines) {
n = v / 2 + 1;
if (v % 2 != 0) {
@ -87,11 +89,11 @@ ChartRulersData::ChartRulersData(
}
lines.resize(n);
const auto diffAbsoluteValue = int((n - 1) * step);
const auto diffAbsoluteValue = ChartValue((n - 1) * step);
const auto skipFloatValues = (step / rightRatio) < 1;
for (auto i = 0; i < n; i++) {
auto &line = lines[i];
const auto value = int(i * step);
const auto value = ChartValue(i * step);
line.absoluteValue = newMinHeight + value;
line.relativeValue = 1. - value / float64(diffAbsoluteValue);
line.caption = leftCustomCaption
@ -103,7 +105,7 @@ ChartRulersData::ChartRulersData(
? rightCustomCaption(line.absoluteValue)
: (!skipFloatValues)
? Format(v)
: ((v - int(v)) < 0.01)
: ((v - ChartValue(v)) < 0.01)
? Format(v)
: QString();
}
@ -112,8 +114,8 @@ ChartRulersData::ChartRulersData(
}
void ChartRulersData::computeRelative(
int newMaxHeight,
int newMinHeight) {
ChartValue newMaxHeight,
ChartValue newMinHeight) {
for (auto &line : lines) {
line.relativeValue = 1.
- ((line.absoluteValue - newMinHeight)
@ -121,10 +123,10 @@ void ChartRulersData::computeRelative(
}
}
int ChartRulersData::LookupHeight(int maxValue) {
ChartValue ChartRulersData::LookupHeight(ChartValue maxValue) {
const auto v = (maxValue > 100) ? Round(maxValue) : maxValue;
const auto step = int(std::ceil(v / kStep));
const auto step = ChartValue(std::ceil(v / kStep));
return step * kStep;
}

View File

@ -7,23 +7,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "statistics/statistics_types.h"
namespace Statistic {
struct ChartRulersData final {
public:
ChartRulersData(
int newMaxHeight,
int newMinHeight,
ChartValue newMaxHeight,
ChartValue newMinHeight,
bool useMinHeight,
float64 rightRatio,
Fn<QString(float64)> leftCustomCaption = nullptr,
Fn<QString(float64)> rightCustomCaption = nullptr);
void computeRelative(
int newMaxHeight,
int newMinHeight);
ChartValue newMaxHeight,
ChartValue newMinHeight);
[[nodiscard]] static int LookupHeight(int maxValue);
[[nodiscard]] static ChartValue LookupHeight(ChartValue maxValue);
struct Line final {
float64 absoluteValue = 0.;

View File

@ -1157,7 +1157,7 @@ void ChartWidget::setupDetails() {
return;
}
const auto maxAbsoluteValue = [&] {
auto maxValue = 0;
auto maxValue = ChartValue(0);
for (const auto &l : _chartData.lines) {
maxValue = std::max(l.maxValue, maxValue);
}

View File

@ -14,7 +14,7 @@ constexpr auto kMinArraySize = size_t(30);
} // namespace
SegmentTree::SegmentTree(std::vector<int> array)
SegmentTree::SegmentTree(std::vector<ChartValue> array)
: _array(std::move(array)) {
if (_array.size() < kMinArraySize) {
return;
@ -28,7 +28,7 @@ SegmentTree::SegmentTree(std::vector<int> array)
build(1, 0, _array.size());
}
void SegmentTree::build(int v, int from, int size) {
void SegmentTree::build(ChartValue v, int from, int size) {
_heap[v].from = from;
_heap[v].to = (from + size - 1);
@ -48,9 +48,9 @@ void SegmentTree::build(int v, int from, int size) {
}
}
int SegmentTree::rMaxQ(int from, int to) {
ChartValue SegmentTree::rMaxQ(int from, int to) {
if (_array.size() < kMinArraySize) {
auto max = 0;
auto max = ChartValue(0);
from = std::max(from, 0);
to = std::min(to, int(_array.size() - 1));
for (auto i = from; i <= to; i++) {
@ -61,7 +61,7 @@ int SegmentTree::rMaxQ(int from, int to) {
return rMaxQ(1, from, to);
}
int SegmentTree::rMaxQ(int v, int from, int to) {
ChartValue SegmentTree::rMaxQ(ChartValue v, int from, int to) {
const auto &n = _heap[v];
// If you did a range update that contained this node,
// you can infer the Min value without going down the tree.
@ -84,9 +84,9 @@ int SegmentTree::rMaxQ(int v, int from, int to) {
return 0;
}
int SegmentTree::rMinQ(int from, int to) {
ChartValue SegmentTree::rMinQ(int from, int to) {
if (_array.size() < kMinArraySize) {
auto min = std::numeric_limits<int>::max();
auto min = std::numeric_limits<ChartValue>::max();
from = std::max(from, 0);
to = std::min(to, int(_array.size() - 1));
for (auto i = from; i <= to; i++) {
@ -97,7 +97,7 @@ int SegmentTree::rMinQ(int from, int to) {
return rMinQ(1, from, to);
}
int SegmentTree::rMinQ(int v, int from, int to) {
ChartValue SegmentTree::rMinQ(ChartValue v, int from, int to) {
const auto &n = _heap[v];
// If you did a range update that contained this node,
// you can infer the Min value without going down the tree.
@ -117,10 +117,10 @@ int SegmentTree::rMinQ(int v, int from, int to) {
return std::min(leftMin, rightMin);
}
return std::numeric_limits<int>::max();
return std::numeric_limits<ChartValue>::max();
}
void SegmentTree::propagate(int v) {
void SegmentTree::propagate(ChartValue v) {
auto &n = _heap[v];
if (n.pendingVal) {
@ -131,7 +131,7 @@ void SegmentTree::propagate(int v) {
}
}
void SegmentTree::change(SegmentTree::Node &n, int value) {
void SegmentTree::change(SegmentTree::Node &n, ChartValue value) {
n.pendingVal = { value, true };
n.sum = n.size() * value;
n.max = value;

View File

@ -7,12 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "statistics/statistics_types.h"
namespace Statistic {
class SegmentTree final {
public:
SegmentTree() = default;
SegmentTree(std::vector<int> array);
SegmentTree(std::vector<ChartValue> array);
[[nodiscard]] bool empty() const {
return _array.empty();
@ -21,20 +23,20 @@ public:
return !empty();
}
[[nodiscard]] int rMaxQ(int from, int to);
[[nodiscard]] int rMinQ(int from, int to);
[[nodiscard]] ChartValue rMaxQ(int from, int to);
[[nodiscard]] ChartValue rMinQ(int from, int to);
private:
struct Node final {
int sum = 0;
int max = 0;
int min = 0;
ChartValue sum = 0;
ChartValue max = 0;
ChartValue min = 0;
struct PendingVal {
[[nodiscard]] explicit operator bool() const {
return available;
}
int value = 0;
ChartValue value = 0;
bool available = false;
};
PendingVal pendingVal;
@ -47,12 +49,12 @@ private:
}
};
void build(int v, int from, int size);
void propagate(int v);
void change(Node &n, int value);
void build(ChartValue v, int from, int size);
void propagate(ChartValue v);
void change(Node &n, ChartValue value);
[[nodiscard]] int rMaxQ(int v, int from, int to);
[[nodiscard]] int rMinQ(int v, int from, int to);
[[nodiscard]] ChartValue rMaxQ(ChartValue v, int from, int to);
[[nodiscard]] ChartValue rMinQ(ChartValue v, int from, int to);
[[nodiscard]] bool contains(int from1, int to1, int from2, int to2) const;
[[nodiscard]] bool intersects(
@ -61,7 +63,7 @@ private:
int from2,
int to2) const;
std::vector<int> _array;
std::vector<ChartValue> _array;
std::vector<Node> _heap;
};

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/debug_log.h"
#include "data/data_statistics_chart.h"
#include "statistics/statistics_types.h"
#include <QtCore/QJsonArray>
#include <QtCore/QJsonDocument>
@ -61,7 +62,7 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
line.isHiddenOnStart = ranges::contains(hiddenLines, columnId);
line.y.resize(length);
for (auto i = 0; i < length; i++) {
const auto value = int(base::SafeRound(
const auto value = ChartValue(base::SafeRound(
array.at(i + 1).toDouble()));
line.y[i] = value;
if (value > line.maxValue) {

View File

@ -0,0 +1,14 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Statistic {
using ChartValue = int64;
} // namespace Statistic

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_statistics_chart.h"
#include "statistics/chart_lines_filter_controller.h"
#include "statistics/statistics_types.h"
namespace Statistic {
@ -71,11 +72,11 @@ AbstractChartView::HeightLimits DefaultHeightLimits(
const std::shared_ptr<LinesFilterController> &linesFilter,
Data::StatisticalChart &chartData,
Limits xIndices) {
auto minValue = std::numeric_limits<int>::max();
auto maxValue = 0;
auto minValue = std::numeric_limits<ChartValue>::max();
auto maxValue = ChartValue(0);
auto minValueFull = std::numeric_limits<int>::max();
auto maxValueFull = 0;
auto minValueFull = std::numeric_limits<ChartValue>::max();
auto maxValueFull = ChartValue(0);
for (auto &l : chartData.lines) {
if (!linesFilter->isEnabled(l.id)) {
continue;
@ -83,11 +84,11 @@ AbstractChartView::HeightLimits DefaultHeightLimits(
const auto r = ratios.ratio(l.id);
const auto lineMax = l.segmentTree.rMaxQ(xIndices.min, xIndices.max);
const auto lineMin = l.segmentTree.rMinQ(xIndices.min, xIndices.max);
maxValue = std::max(int(lineMax * r), maxValue);
minValue = std::min(int(lineMin * r), minValue);
maxValue = std::max(ChartValue(lineMax * r), maxValue);
minValue = std::min(ChartValue(lineMin * r), minValue);
maxValueFull = std::max(int(l.maxValue * r), maxValueFull);
minValueFull = std::min(int(l.minValue * r), minValueFull);
maxValueFull = std::max(ChartValue(l.maxValue * r), maxValueFull);
minValueFull = std::min(ChartValue(l.minValue * r), minValueFull);
}
if (maxValue == minValue) {
maxValue = chartData.maxValue;

View File

@ -256,9 +256,9 @@ AbstractChartView::HeightLimits BarChartView::heightLimits(
if (_cachedHeightLimits.ySum.empty()) {
_cachedHeightLimits.ySum.reserve(chartData.x.size());
auto maxValueFull = 0;
auto maxValueFull = ChartValue(0);
for (auto i = 0; i < chartData.x.size(); i++) {
auto sum = 0;
auto sum = ChartValue(0);
for (const auto &line : chartData.lines) {
if (linesFilterController()->isEnabled(line.id)) {
sum += line.y[i];
@ -276,7 +276,7 @@ AbstractChartView::HeightLimits BarChartView::heightLimits(
_cachedHeightLimits.ySumSegmentTree.rMaxQ(
xIndices.min,
xIndices.max),
1);
ChartValue(1));
return {
.full = _cachedHeightLimits.full,
.ranged = { 0., float64(max) },

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "statistics/segment_tree.h"
#include "statistics/statistics_common.h"
#include "statistics/statistics_types.h"
#include "statistics/view/abstract_chart_view.h"
#include "ui/effects/animation_value.h"
@ -48,7 +49,7 @@ private:
struct {
Limits full;
std::vector<int> ySum;
std::vector<ChartValue> ySum;
SegmentTree ySumSegmentTree;
} _cachedHeightLimits;

View File

@ -81,7 +81,7 @@ PiePartData PiePartsPercentageByIndices(
sums.reserve(chartData.lines.size());
auto totalSum = 0.;
for (const auto &line : chartData.lines) {
auto sum = 0;
auto sum = ChartValue(0);
for (auto i = xIndices.min; i <= xIndices.max; i++) {
sum += line.y[i];
}

View File

@ -165,8 +165,8 @@ void StackLinearChartView::prepareZoom(
_transition.zoomedOutXIndices = c.xIndices;
_transition.zoomedOutXPercentage = c.xPercentageLimits;
} else if (step == TransitionStep::PrepareToZoomIn) {
const auto &[zoomedStart, zoomedEnd] =
_transition.zoomedOutXIndices;
const auto &[zoomedStart, zoomedEnd]
= _transition.zoomedOutXIndices;
_transition.lines = std::vector<Transition::TransitionLine>(
c.chartData.lines.size(),
Transition::TransitionLine());
@ -624,7 +624,7 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) {
if (selectedLineIndex >= 0) {
const auto &line = c.chartData.lines[selectedLineIndex];
auto sum = 0;
auto sum = ChartValue(0);
for (auto i = zoomedStart; i <= zoomedEnd; i++) {
sum += line.y[i];
}
@ -669,8 +669,8 @@ void StackLinearChartView::paintZoomedFooter(
0);
const auto next = std::clamp(i + offset, zoomedStart, zoomedEnd);
const auto xPointPercentage =
(xPercentage[next] - xPercentage[zoomedStart])
const auto xPointPercentage
= (xPercentage[next] - xPercentage[zoomedStart])
/ (xPercentage[zoomedEnd] - xPercentage[zoomedStart]);
const auto xPoint = leftStart + width * xPointPercentage;

View File

@ -205,6 +205,7 @@ PRIVATE
statistics/statistics_data_deserialize.h
statistics/statistics_format_values.cpp
statistics/statistics_format_values.h
statistics/statistics_types.h
statistics/view/abstract_chart_view.cpp
statistics/view/abstract_chart_view.h
statistics/view/bar_chart_view.cpp