/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file ValueTimeLine.h14/// @author Christian Roessel15/// @author Daniel Krajzewicz16/// @author Michael Behrisch17/// @date Sept 200218///19// A list of time ranges with assigned values20/****************************************************************************/21#pragma once22#include <config.h>23#include <map>24#include <cassert>25#include <utility>26#include <utils/common/SUMOTime.h>27282930// ===========================================================================31// class definitions32// ===========================================================================33/**34* @class ValueTimeLine35*36* A time line being a sorted container of non-overlapping time-ranges37* with assigned values. The container is sorted by the first value of the38* time-range while being filled. Every new inserted time range39* may overwrite or split one or multiple earlier intervals.40*/41template<typename T>42class ValueTimeLine {43public:44/// @brief Constructor45ValueTimeLine() { }4647/// @brief Destructor48~ValueTimeLine() { }4950/** @brief Adds a value for a time interval into the container.51*52* Make sure that begin >= 0 and begin < end.53*54* @param[in] begin the start time of the time range (inclusive)55* @param[in] end the end time of the time range (exclusive)56* @param[in] value the value to store57*/58void add(double begin, double end, T value) {59assert(begin >= 0);60assert(begin < end);61// inserting strictly before the first or after the last interval (includes empty case)62if (myValues.upper_bound(begin) == myValues.end() ||63myValues.upper_bound(end) == myValues.begin()) {64myValues[begin] = std::make_pair(true, value);65myValues[end] = std::make_pair(false, value);66return;67}68// our end already has a value69typename TimedValueMap::iterator endIt = myValues.find(end);70if (endIt != myValues.end()) {71myValues.erase(myValues.upper_bound(begin), endIt);72myValues[begin] = std::make_pair(true, value);73return;74}75// we have at least one entry strictly before our end76endIt = myValues.lower_bound(end);77--endIt;78ValidValue oldEndValue = endIt->second;79myValues.erase(myValues.upper_bound(begin), myValues.lower_bound(end));80myValues[begin] = std::make_pair(true, value);81myValues[end] = oldEndValue;82}8384/** @brief Returns the value for the given time.85*86* There is no bounds checking applied! If there was no value87* set, the return value is undefined, the method may even segfault.88*89* @param[in] the time for which the value should be retrieved90* @return the value for the time91*/92T getValue(double time) const {93assert(myValues.size() != 0);94typename TimedValueMap::const_iterator it = myValues.upper_bound(time);95assert(it != myValues.begin());96--it;97return it->second.second;98}99100/** @brief Returns whether a value for the given time is known.101*102* This method implements the bounds checking. It returns true103* if and only if an explicit value was set for the given time104* using add. Default values stemming from fillGaps are not105* considered valid.106*107* @param[in] the time for which the value should be retrieved108* @return whether a valid value was set109*/110bool describesTime(double time) const {111typename TimedValueMap::const_iterator afterIt = myValues.upper_bound(time);112if (afterIt == myValues.begin()) {113return false;114}115--afterIt;116return afterIt->second.first;117}118119/** @brief Returns the time point at which the value changes.120*121* If the two input parameters lie in two consecutive time122* intervals, this method returns the point at which the123* interval changes. In any other case -1 is returned.124*125* @param[in] low the time in the first interval126* @param[in] high the time in the second interval127* @return the split point128*/129double getSplitTime(double low, double high) const {130typename TimedValueMap::const_iterator afterLow = myValues.upper_bound(low);131typename TimedValueMap::const_iterator afterHigh = myValues.upper_bound(high);132--afterHigh;133if (afterLow == afterHigh) {134return afterLow->first;135}136return -1;137}138139/** @brief Sets a default value for all unset intervals.140*141* @param[in] value the value to store142* @param[in] extendOverBoundaries whether the first/last value should be valid for later / earlier times as well143*/144void fillGaps(T value, bool extendOverBoundaries = false) {145for (typename TimedValueMap::iterator it = myValues.begin(); it != myValues.end(); ++it) {146if (!it->second.first) {147it->second.second = value;148}149}150if (extendOverBoundaries && !myValues.empty()) {151typename TimedValueMap::iterator it = --myValues.end();152if (!it->second.first) {153myValues.erase(it, myValues.end());154}155value = myValues.begin()->second.second;156}157myValues[-1] = std::make_pair(false, value);158}159160private:161/// @brief Value of time line, indicating validity.162typedef std::pair<bool, T> ValidValue;163164/// @brief Sorted map from start of intervals to values.165typedef std::map<double, ValidValue> TimedValueMap;166167/// @brief The list of time periods (with values)168TimedValueMap myValues;169170};171172173