OpenTTD Source 20260206-master-g4d4e37dbf1
history_func.hpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#ifndef HISTORY_FUNC_HPP
11#define HISTORY_FUNC_HPP
12
14#include "../core/math_func.hpp"
16#include "history_type.hpp"
17
18void UpdateValidHistory(ValidHistoryMask &valid_history, const HistoryRange &hr, uint cur_month);
19bool IsValidHistory(ValidHistoryMask valid_history, const HistoryRange &hr, uint age);
20
28template <typename T>
29T SumHistory(typename std::span<const T> history);
30
40template <typename T>
41void RotateHistory(HistoryData<T> &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint cur_month)
42{
43 if (hr.hr != nullptr) RotateHistory(history, valid_history, *hr.hr, cur_month);
44 if (cur_month % hr.total_division != 0) return;
45
46 std::move_backward(std::next(std::begin(history), hr.first), std::next(std::begin(history), hr.last - 1), std::next(std::begin(history), hr.last));
47
48 if (hr.total_division == 1) {
49 history[hr.first] = history[hr.first - 1];
50 history.front() = {};
51 } else if (HasBit(valid_history, hr.first - hr.division)) {
52 auto first = std::next(std::begin(history), hr.first - hr.division);
53 auto last = std::next(first, hr.division);
54 history[hr.first] = SumHistory<T>(std::span{first, last});
55 }
56}
57
63template <typename T, typename Taccrued>
65{
66 T result = ClampTo<T>(total / std::max(1U, TimerGameEconomy::days_since_last_month));
67 total = 0;
68 return result;
69}
70
81template <typename T>
82bool GetHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint age, T &result)
83{
84 if (hr.hr == nullptr) {
85 if (age < hr.periods) {
86 uint slot = hr.first + age;
87 result = history[slot];
88 return HasBit(valid_history, slot);
89 }
90 } else {
91 if (age * hr.division < static_cast<uint>(hr.hr->periods - hr.division)) {
92 bool is_valid = false;
93 std::array<T, HISTORY_MAX_DIVISION> tmp_result; // No need to clear as we fill every element we use.
94 uint start = age * hr.division + ((TimerGameEconomy::month / hr.hr->division) % hr.division);
95 for (auto i = start; i != start + hr.division; ++i) {
96 is_valid |= GetHistory(history, valid_history, *hr.hr, i, tmp_result[i - start]);
97 }
98 result = SumHistory<T>(std::span{std::begin(tmp_result), hr.division});
99 return is_valid;
100 }
101 if (age < hr.periods) {
102 uint slot = hr.first + age - ((hr.hr->periods / hr.division) - 1);
103 result = history[slot];
104 return HasBit(valid_history, slot);
105 }
106 }
107 NOT_REACHED();
108}
109
117template <uint N, typename T, typename... Tfillers>
118void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, const HistoryRange &hr, Tfillers &&... fillers)
119{
120 T result{};
121 for (uint i = 0; i != N; ++i) {
122 if (GetHistory(history, valid_history, hr, N - i - 1, result)) {
123 (fillers.Fill(i, result), ...);
124 } else {
125 (fillers.MakeInvalid(i), ...);
126 }
127 }
128}
129
137template <uint N, typename T, typename... Tfillers>
138void FillFromHistory(const HistoryData<T> *history, ValidHistoryMask valid_history, const HistoryRange &hr, Tfillers &&... fillers)
139{
140 if (history != nullptr) {
141 FillFromHistory<N>(*history, valid_history, hr, std::forward<Tfillers &&>(fillers)...);
142 return;
143 }
144
145 /* History isn't present, fill zero or invalid instead. */
146 for (uint i = 0; i != N; ++i) {
147 if (IsValidHistory(valid_history, hr, N - i - 1)) {
148 (fillers.MakeZero(i), ...);
149 } else {
150 (fillers.MakeInvalid(i), ...);
151 }
152 }
153}
154
155#endif /* HISTORY_FUNC_HPP */
Functions related to bit mathematics.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static Month month
Current month (0..11).
static uint days_since_last_month
Number of days that have elapsed since the last month.
void UpdateValidHistory(ValidHistoryMask &valid_history, const HistoryRange &hr, uint cur_month)
Update mask of valid records for a historical data.
Definition history.cpp:25
T GetAndResetAccumulatedAverage(Taccrued &total)
Get an average value for the previous month, as reset for the next month.
bool GetHistory(const HistoryData< T > &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint age, T &result)
Get historical data.
void RotateHistory(HistoryData< T > &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint cur_month)
Rotate historical data.
T SumHistory(typename std::span< const T > history)
Sum history data elements.
bool IsValidHistory(ValidHistoryMask valid_history, const HistoryRange &hr, uint age)
Test if history data is valid, without extracting data.
Definition history.cpp:47
void FillFromHistory(const HistoryData< T > &history, ValidHistoryMask valid_history, const HistoryRange &hr, Tfillers &&... fillers)
Fill some data with historical data.
Types for storing historical data.
std::array< T, HISTORY_RECORDS > HistoryData
Container type for storing history data.
uint64_t ValidHistoryMask
Mask of valid history records.
Integer math functions.
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
const uint8_t last
Index of last element in history data.
const uint8_t total_division
Number of divisions of the initial history range.
const uint8_t division
Number of divisions of the previous history range.
const uint8_t first
Index of first element in history data.
const uint8_t periods
Number of periods for this range.
Definition of the game-economy-timer.