OpenTTD Source 20250905-master-g122023be8d
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 <http://www.gnu.org/licenses/>.
6 */
7
10#ifndef HISTORY_FUNC_HPP
11#define HISTORY_FUNC_HPP
12
13#include "../core/bitmath_func.hpp"
14#include "../core/math_func.hpp"
15#include "../timer/timer_game_economy.h"
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
82template <typename T>
83bool GetHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint age, T &result)
84{
85 if (hr.hr == nullptr) {
86 if (age < hr.periods) {
87 uint slot = hr.first + age;
88 result = history[slot];
89 return HasBit(valid_history, slot);
90 }
91 } else {
92 if (age * hr.division < static_cast<uint>(hr.hr->periods - hr.division)) {
93 bool is_valid = false;
94 std::array<T, HISTORY_MAX_DIVISION> tmp_result; // No need to clear as we fill every element we use.
95 uint start = age * hr.division + ((TimerGameEconomy::month / hr.hr->division) % hr.division);
96 for (auto i = start; i != start + hr.division; ++i) {
97 is_valid |= GetHistory(history, valid_history, *hr.hr, i, tmp_result[i - start]);
98 }
99 result = SumHistory<T>(std::span{std::begin(tmp_result), hr.division});
100 return is_valid;
101 }
102 if (age < hr.periods) {
103 uint slot = hr.first + age - ((hr.hr->periods / hr.division) - 1);
104 result = history[slot];
105 return HasBit(valid_history, slot);
106 }
107 }
108 NOT_REACHED();
109}
110
118template <uint N, typename T, typename... Tfillers>
119void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, const HistoryRange &hr, Tfillers &&... fillers)
120{
121 T result{};
122 for (uint i = 0; i != N; ++i) {
123 if (GetHistory(history, valid_history, hr, N - i - 1, result)) {
124 (fillers.Fill(i, result), ...);
125 } else {
126 (fillers.MakeInvalid(i), ...);
127 }
128 }
129}
130
138template <uint N, typename T, typename... Tfillers>
139void FillFromHistory(const HistoryData<T> *history, ValidHistoryMask valid_history, const HistoryRange &hr, Tfillers &&... fillers)
140{
141 if (history != nullptr) {
142 FillFromHistory<N>(*history, valid_history, hr, std::forward<Tfillers &&>(fillers)...);
143 return;
144 }
145
146 /* History isn't present, fill zero or invalid instead. */
147 for (uint i = 0; i != N; ++i) {
148 if (IsValidHistory(valid_history, hr, N - i - 1)) {
149 (fillers.MakeZero(i), ...);
150 } else {
151 (fillers.MakeInvalid(i), ...);
152 }
153 }
154}
155
156#endif /* HISTORY_FUNC_HPP */
debug_inline 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.
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.