#pragma once #include "base/macros.hpp" #include "base/newtype.hpp" #include "base/visitor.hpp" #include #include #include #include #include #include #include #include #include #include "3party/just_gtfs/just_gtfs.h" // This is the implementation of the Schedule class and its helpers for handling transit service // days and stops timetables. namespace routing { namespace transit { template class Serializer; template class Deserializer; template class FixedSizeSerializer; template class FixedSizeDeserializer; } // namespace transit } // namespace routing namespace transit { #define DECLARE_SCHEDULE_TYPES_FRIENDS \ template \ friend class routing::transit::Serializer; \ template \ friend class routing::transit::Deserializer; \ template \ friend class routing::transit::FixedSizeSerializer; \ template \ friend class routing::transit::FixedSizeDeserializer; // Status of some transit itinerary (e.g. line) in the moment of time. enum class Status : uint8_t { Open, Closed, Unknown }; std::string DebugPrint(Status const & status); struct Date { Date() = default; Date(uint32_t year, uint8_t month, uint16_t day) : m_year(year), m_month(month), m_day(day) {} DECLARE_SCHEDULE_TYPES_FRIENDS DECLARE_VISITOR_AND_DEBUG_PRINT(Date, visitor(m_year, "y"), visitor(m_month, "m"), visitor(m_day, "d")) uint32_t m_year = 0; uint8_t m_month = 0; uint16_t m_day = 0; }; struct Time { Time() = default; Time(uint8_t hour, uint8_t minute, uint8_t second) : m_hour(hour), m_minute(minute), m_second(second) { } DECLARE_SCHEDULE_TYPES_FRIENDS DECLARE_VISITOR_AND_DEBUG_PRINT(Time, visitor(m_hour, "h"), visitor(m_minute, "m"), visitor(m_second, "s")) uint8_t m_hour = 0; uint8_t m_minute = 0; uint8_t m_second = 0; }; using WeekSchedule = std::array; enum WeekDays { Sunday = 0, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }; // Service dates specified using a weekly schedule with start and end dates. Dates range is // specified by the start_date and end_date fields in the GTFS calendar.txt. // Dates interval and open/closed states for week days are stored |m_data|. class DatesInterval { public: DatesInterval() = default; explicit DatesInterval(gtfs::CalendarItem const & calendarItem); explicit DatesInterval(uint32_t data); bool operator==(DatesInterval const & rhs) const; std::tuple Extract() const; uint32_t GetRaw() const { return m_data; } Status GetStatusInInterval(Date const & date, uint8_t wdIndex) const; private: DECLARE_SCHEDULE_TYPES_FRIENDS DECLARE_VISITOR_AND_DEBUG_PRINT(DatesInterval, visitor(m_data, "m_data")) // From greater indexes to smaller: year1, month1, day1, years delta (year2 - year1), month2, // day2, weekdays. Week indexes start from sunday = 0. uint32_t m_data = 0; }; struct DatesIntervalHasher { size_t operator()(DatesInterval const & key) const { return key.GetRaw(); } }; // Exceptions for the services defined in the calendar.txt. If calendar.txt is not used, it may // contain all dates of service. Exception date and its type (added/removed) are stored in |m_data|. class DateException { public: DateException() = default; DateException(gtfs::Date const & date, gtfs::CalendarDateException const & dateException); explicit DateException(uint16_t data); bool operator==(DateException const & rhs) const; std::tuple Extract() const; uint32_t GetRaw() const { return m_data; } Status GetExceptionStatus(Date const & date) const; private: DECLARE_SCHEDULE_TYPES_FRIENDS DECLARE_VISITOR_AND_DEBUG_PRINT(DateException, visitor(m_data, "m_data")) // From greater indexes to smaller: year, month, day, status uint16_t m_data = 0; }; struct DateExceptionHasher { size_t operator()(DateException const & key) const { return key.GetRaw(); } }; // Time range for lines frequencies or stop timetables. Start time and end time are stored in // m_data. class TimeInterval { public: TimeInterval() = default; TimeInterval(gtfs::Time const & startTime, gtfs::Time const & endTime); explicit TimeInterval(uint64_t data); bool operator<(TimeInterval const & rhs) const; bool operator==(TimeInterval const & rhs) const; std::pair Extract() const; uint64_t GetRaw() const { return m_data; } Status GetTimeStatus(Time const & time) const; private: DECLARE_SCHEDULE_TYPES_FRIENDS DECLARE_VISITOR_AND_DEBUG_PRINT(TimeInterval, visitor(m_data, "m_data")) // From greater indexes to smaller: start time, end time. uint64_t m_data = 0; }; using Frequency = uint32_t; inline Frequency constexpr kDefaultFrequency = 0; // Headway (interval between times that a vehicle arrives at and departs from stops) for // headway-based service or a compressed representation of fixed-schedule service. For each time // range there is a frequency value. class FrequencyIntervals { public: FrequencyIntervals() = default; FrequencyIntervals(gtfs::Frequencies const & frequencies); bool operator==(FrequencyIntervals const & rhs) const; void AddInterval(TimeInterval const & timeInterval, Frequency frequency); Frequency GetFrequency(Time const & time) const; std::map const & GetFrequencies() const; private: DECLARE_SCHEDULE_TYPES_FRIENDS DECLARE_VISITOR_AND_DEBUG_PRINT(FrequencyIntervals, visitor(m_intervals, "m_intervals")) std::map m_intervals; }; using DatesIntervals = std::unordered_map; using DatesExceptions = std::unordered_map; // Line schedule with line service days (as DatesInterval ranges) and exceptions in service days // (as DateException items). For each date there are frequency intervals (time ranges with headway // in seconds). This schedule is useful while building transit routes based on particular route // start time. class Schedule { public: bool operator==(Schedule const & rhs) const; void AddDatesInterval(gtfs::CalendarItem const & calendarItem, gtfs::Frequencies const & frequencies); void AddDateException(gtfs::Date const & date, gtfs::CalendarDateException const & dateException, gtfs::Frequencies const & frequencies); Status GetStatus(time_t const & time) const; Frequency GetFrequency(time_t const & time) const; Frequency GetFrequency() const { return m_defaultFrequency; } DatesIntervals const & GetServiceIntervals() const; DatesExceptions const & GetServiceExceptions() const; void AddDatesInterval(DatesInterval const & interval, FrequencyIntervals const & frequencies); void AddDateException(DateException const & dateException, FrequencyIntervals const & frequencies); void SetDefaultFrequency(Frequency const & frequency) { m_defaultFrequency = frequency; } private: std::pair GetDateAndWeekIndex(time_t const & time) const; std::tuple GetDateTimeAndWeekIndex(time_t const & time) const; DECLARE_SCHEDULE_TYPES_FRIENDS DECLARE_VISITOR_AND_DEBUG_PRINT(Schedule, visitor(m_serviceIntervals, "m_serviceIntervals"), visitor(m_serviceExceptions, "m_serviceExceptions"), visitor(m_defaultFrequency, "m_defaultFrequency")) DatesIntervals m_serviceIntervals; DatesExceptions m_serviceExceptions; Frequency m_defaultFrequency = kDefaultFrequency; }; #undef DECLARE_SCHEDULE_TYPES_FRIENDS } // namespace transit