diff --git a/Timetable/Line.cs b/Timetable/Line.cs index 79e67c6..7dc4df6 100644 --- a/Timetable/Line.cs +++ b/Timetable/Line.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using LanguageExt; namespace Timetable; @@ -14,18 +15,17 @@ public partial record Line /// public required string Name { get; init; } - private readonly Route[] _routes = null!; // Will be set by *required* init-er below. + private readonly Arr _routes = null!; // Will be set by *required* init-er below. /// /// All s assigned to this . /// - public required Route[] Routes + public required IReadOnlyList Routes { get => _routes; init { - _routes = value; - foreach (var route in Routes) + foreach (var route in value) { route.Line = this; // Validate that stop distances length matches route length. @@ -33,6 +33,7 @@ public required Route[] Routes route.TimeProfiles.All(profile => profile.StopDistances.Length == route.StopPositions.Length - 1), $"For {this.Name}, {route.ToString()}, at least one time profile has an incorrect stop distance count."); } + _routes = Arr.createRange(value); } } @@ -82,10 +83,16 @@ public required Route[] Routes public IEnumerable TripsOfRouteIndex(Index routeIndex) => Trips.Where(trip => trip.Route == Routes[routeIndex]); + private readonly Arr _tripsCreate = null!; // Will be set by *required* init-er below. + /// /// All s used to specify which s exist for this . /// - public required ICollection TripsCreate { get; init; } + public required IReadOnlyList TripsCreate + { + get => _tripsCreate; + init => _tripsCreate = Arr.createRange(value); + } /// /// Which medium of transportation is the one used by this . @@ -102,10 +109,16 @@ public IEnumerable TripsOfRouteIndex(Index routeIndex) => /// public IEnumerable MainRoutes => MainRouteIndices.Select(index => Routes[index]); + private readonly Arr _mainRouteIndices = null!; // Will be set by *required* init-er below. + /// - /// Specifies the indices of the s that are considers . + /// Specifies the indices of the s that are considered . /// - public required Index[] MainRouteIndices { get; init; } + public required IReadOnlyList MainRouteIndices + { + get => _mainRouteIndices; + init => _mainRouteIndices = Arr.createRange(value); + } /// /// s that are considered to be representative s for this . @@ -115,15 +128,28 @@ public IEnumerable TripsOfRouteIndex(Index routeIndex) => /// public IEnumerable OverviewRoutes => OverviewRouteIndices.Select(index => Routes[index]); + private readonly Arr _overviewRouteIndices = null!; // Will be set by *required* init-er below. + /// /// Specifies the indices of the s that are considers . /// - public required Index[] OverviewRouteIndices { get; init; } + public required IReadOnlyList OverviewRouteIndices + { + get => _overviewRouteIndices; + init => _overviewRouteIndices = Arr.createRange(value); + } + + private readonly HashMap _annotations = HashMap.Empty; /// /// Manual annotations, indexed by their symbol, mapping to their text. /// - public Dictionary Annotations { get; init; } = new(); + // TODO: Find a better way here, potentially with a native value equality dictionary. + public IReadOnlyDictionary Annotations + { + get => _annotations.ToReadOnlyDictionary(); + init => _annotations = HashMap.createRange(value); + } /// /// The typical time of day where this operates. diff --git a/Timetable/Route.cs b/Timetable/Route.cs index 3e47ec2..abc35ff 100644 --- a/Timetable/Route.cs +++ b/Timetable/Route.cs @@ -1,3 +1,8 @@ +using System.Diagnostics.Contracts; +using System.Numerics; +using System.Runtime.CompilerServices; +using LanguageExt; + namespace Timetable; public partial record Line @@ -15,15 +20,27 @@ public partial record Route internal Line? Line { get; set; } + private readonly Arr _stopPositions = null!; // Will be set by *required* init-er below. + /// /// The s where this route calls at. /// - public required Stop.Position[] StopPositions { get; init; } + public required IReadOnlyList StopPositions + { + get => _stopPositions; + init => _stopPositions = Arr.createRange(value); + } + + private readonly Arr _timeProfiles = null!; // Will be set by *required* init-er below. /// /// All the existing timing patterns for this route. /// - public required TimeProfile[] TimeProfiles { get; init; } + public required IReadOnlyList TimeProfiles + { + get => _timeProfiles; + init => _timeProfiles = Arr.createRange(value); + } /// /// A text to be displayed alongside this route. @@ -93,7 +110,7 @@ public bool TryGetIndexOfStopFirst(Stop stop, out int index) /// The to check for. /// Only consider departures, i.e. the last stop of this route is ignored. public bool DoesStopAt(Stop stop, bool onlyDepartures) => StopPositions - .Take(StopPositions.Length - (onlyDepartures + .Take(StopPositions.Count - (onlyDepartures ? /* when we only want departures, the last stop is no longer relevant */ 1 : 0)).Select(pos => pos.Stop).Contains(stop); @@ -168,11 +185,16 @@ public Route WithoutStop(Stop stopToExclude) => StopPositions.Any(pos => pos.Sto /// if those two stations exist and are next to each other. /// /// - public Route WithStopBetween(Stop before, Stop.Position inserted, Stop after, TimeSpan firstTime, TimeSpan secondTime) + public Route WithStopBetween(Stop before, Stop.Position inserted, Stop after, TimeSpan firstTime, + TimeSpan secondTime) { - var beforeIndex = Array.IndexOf(StopPositions, before); + List list = [1, 2, 3]; + IReadOnlyList d = list; + var x = list[1..]; + Console.WriteLine(x.Count); + var beforeIndex = StopPositions.IndexOf(before); if (beforeIndex == -1) return this; - var afterIndex = Array.IndexOf(StopPositions, after); + var afterIndex = StopPositions.IndexOf(after); if (afterIndex == -1) return this; if (afterIndex != beforeIndex + 1) return this; Stop.Position[] insertedPositions = @@ -206,3 +228,13 @@ public Route WithStopBetween(Stop before, Stop.Position inserted, Stop after, Ti .Select(trip => int.PopCount((int)(trip.DaysOfOperation & days))).Sum(); } } + +file static class CollectionExtensions +{ + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOf(this IReadOnlyList list, T element) where T : IEqualityOperators => + list is Arr arr + ? arr.IndexOf(element) + : list.Index().Where(tuple => tuple.Item == element).Select(tuple => tuple.Index).FirstOrDefault(-1); +} diff --git a/Timetable/Stop.cs b/Timetable/Stop.cs index 3c87960..79d89d0 100644 --- a/Timetable/Stop.cs +++ b/Timetable/Stop.cs @@ -1,3 +1,5 @@ +using R4Utils.ValueEqualityCollections; + namespace Timetable; /// @@ -19,10 +21,19 @@ public Stop() /// public required string InitialName { private get; init; } + private readonly ValueEqualityCollection<(DateOnly Date, string Name), List<(DateOnly Date, string Name)>> + _nameChanges = null!; // Will be set by *required* init-er below. + /// /// Maps the of a change of name of this to its new name. /// - public List<(DateOnly Date, string Name)> NameChanges { get; init; } = []; + public List<(DateOnly Date, string Name)> NameChanges + { + get => _nameChanges.Underlying; + init => _nameChanges = + value.AsGenericOrderedValueEqualityCollection<(DateOnly Date, string Name), + List<(DateOnly Date, string Name)>>(); + } /// /// The of this . @@ -49,7 +60,8 @@ public string NameAt(DateOnly date) => NameChanges.Count == 0 || NameChanges[0]. private string DisplayNameFor(string name, City referenceCity) => referenceCity == City ? name : $"{City.Name}, {name}"; - private readonly Position[] _positions = null!; // Will be set below. + private readonly ValueEqualityCollection _positions = + Array.Empty().AsGenericOrderedValueEqualityCollection(); /// /// All s of this . @@ -57,10 +69,10 @@ private string DisplayNameFor(string name, City referenceCity) => /// Defaults to a single-element array if omitted. public /*required*/ Position[] Positions { - get => _positions; + get => _positions.Underlying; init { - _positions = value; + _positions = value.AsGenericOrderedValueEqualityCollection(); foreach (var position in _positions) { if (position.Stop is not null) diff --git a/Timetable/TimeProfile.cs b/Timetable/TimeProfile.cs index 07d5d85..a747183 100644 --- a/Timetable/TimeProfile.cs +++ b/Timetable/TimeProfile.cs @@ -1,3 +1,5 @@ +using R4Utils.ValueEqualityCollections; + namespace Timetable; public partial record Line @@ -11,10 +13,17 @@ public partial record Route /// public record TimeProfile { + private readonly ValueEqualityCollection + _stopDistances = null!; // Will be set by *required* init-er below. + /// /// At index i there is the time it takes to travel from stop position i to i+1. /// - public required TimeSpan[] StopDistances { get; init; } + public required TimeSpan[] StopDistances + { + get => _stopDistances.Underlying; + init => _stopDistances = value.AsGenericOrderedValueEqualityCollection(); + } /// /// Get the time it takes to travel from stop index to . diff --git a/Timetable/Timetable.csproj b/Timetable/Timetable.csproj index 6cbad85..d64125a 100644 --- a/Timetable/Timetable.csproj +++ b/Timetable/Timetable.csproj @@ -15,4 +15,8 @@ bin\Release\net8.0\Timetable.xml + + + + diff --git a/Timetable/Trip.cs b/Timetable/Trip.cs index 33f8d14..a5b2e9e 100644 --- a/Timetable/Trip.cs +++ b/Timetable/Trip.cs @@ -1,3 +1,5 @@ +using LanguageExt; + namespace Timetable; public partial record Line @@ -32,25 +34,37 @@ public partial record Trip /// public required DaysOfOperation DaysOfOperation { get; init; } + private readonly Arr _annotations = null!; // Will be set by *required* init-er below. + /// /// All manually (in the timetable) specified for this . /// - public required List Annotations { get; init; } + public required IReadOnlyList Annotations + { + get => _annotations; + init => _annotations = Arr.createRange(value); + } + + private readonly Arr _connections = null!; // Will be set by *required* init-er below. /// /// All through services this participates in. ///

/// This should have 0 (no through service), 1 (start or end of through service), or 2 (middle of a through service) elements. ///
- public required List Connections { private get; init; } + public required IReadOnlyList Connections + { + private get => _connections; + init => _connections = Arr.createRange(value); + } /// /// Translate the trip-create s present on this into trip s. /// /// All s present in the current network, indexed by their id. // Consider adding more validation steps if it becomes a problem. - public IEnumerable GetConnections(IReadOnlyDictionary allLines) => Connections.Select( - connection => new Connection + public IEnumerable GetConnections(IReadOnlyDictionary allLines) => + Connections.Select(connection => new Connection { Type = connection.Type, NotableViaStop = connection.NotableViaStop, diff --git a/Timetable/TripCreate.cs b/Timetable/TripCreate.cs index 1ad2890..6bcc36a 100644 --- a/Timetable/TripCreate.cs +++ b/Timetable/TripCreate.cs @@ -1,3 +1,5 @@ +using LanguageExt; + namespace Timetable; public partial record Line @@ -42,20 +44,32 @@ public TripCreate() [Obsolete($"Use {nameof(AnnotationSymbols)} instead.", false)] public string AnnotationSymbol { - init => AnnotationSymbols.Add(value); + init => _annotationSymbols = Arr.create(value); } + private readonly Arr _annotationSymbols = Arr.empty(); + /// /// The symbols (defined as the keys of ) of the annotations this trip has. /// - public List AnnotationSymbols { get; init; } = []; + public IReadOnlyList AnnotationSymbols + { + get => _annotationSymbols; + init => _annotationSymbols = Arr.createRange(value); + } + + private readonly Arr _connections = Arr.empty(); /// /// All through services this trip participates in. ///

/// This should have 0 (no through service), 1 (start or end of through service), or 2 (middle of a through service) elements. ///
- public List Connections { get; init; } = []; + public IReadOnlyList Connections + { + get => _connections; + init => _connections = Arr.createRange(value); + } /// /// Repeat this instance for every . diff --git a/TimetableConsole/Program.cs b/TimetableConsole/Program.cs new file mode 100644 index 0000000..4496cc5 --- /dev/null +++ b/TimetableConsole/Program.cs @@ -0,0 +1,33 @@ +/* + +using System.Diagnostics; +using Timetable; + +var sw = new Stopwatch(); +sw.Start(); +var history = VipTimetable.VipHistory.History; +var entry = history[0]; +var lines = entry.OrderedLinesById.ToArray(); +var line = lines[0].Value; +var routes = line.Routes; +var route = routes[0]; +var trips = line.TripsOfRouteIndex(0).ToArray(); +var stopTimetableView = new Timetable.Views.StopTimetableView(lines.ToDictionary(), trips, + [DaysOfOperation.Weekday, DaysOfOperation.Weekend], route.StopPositions[0].Stop, new DateOnly(2024, 1, 3)); +sw.Stop(); +Console.WriteLine($"Got {trips.Length} trips for route {route}."); +Console.WriteLine($"Last stop of route 0: {stopTimetableView.LastStopOfRoute(0)}"); +Console.WriteLine($"Took {sw.Elapsed}"); +*/ + +List Test() +{ + List list = [1, 2, 3]; + IReadOnlyList d = list; + var x = list[1..]; + var y = d.Mem + return x; +} + + +Console.WriteLine(Test().Count); \ No newline at end of file diff --git a/TimetableConsole/TimetableConsole.csproj b/TimetableConsole/TimetableConsole.csproj new file mode 100644 index 0000000..e89a5b0 --- /dev/null +++ b/TimetableConsole/TimetableConsole.csproj @@ -0,0 +1,16 @@ + + + + Exe + net9.0 + enable + enable + true + true + + + + diff --git a/TransitUI.sln b/TransitUI.sln index 04f80eb..44ee198 100644 --- a/TransitUI.sln +++ b/TransitUI.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Timetable", "Timetable\Time EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VipTimetable", "VipTimetable\VipTimetable.csproj", "{980D1CB3-74A8-41C0-98B9-BBF543D707EB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimetableConsole", "TimetableConsole\TimetableConsole.csproj", "{571CFDBC-13FB-4D7E-B327-A50B97075C53}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -43,5 +45,9 @@ Global {980D1CB3-74A8-41C0-98B9-BBF543D707EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {980D1CB3-74A8-41C0-98B9-BBF543D707EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {980D1CB3-74A8-41C0-98B9-BBF543D707EB}.Release|Any CPU.Build.0 = Release|Any CPU + {571CFDBC-13FB-4D7E-B327-A50B97075C53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {571CFDBC-13FB-4D7E-B327-A50B97075C53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {571CFDBC-13FB-4D7E-B327-A50B97075C53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {571CFDBC-13FB-4D7E-B327-A50B97075C53}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/TransitUI.sln.DotSettings.user b/TransitUI.sln.DotSettings.user new file mode 100644 index 0000000..5dbbd19 --- /dev/null +++ b/TransitUI.sln.DotSettings.user @@ -0,0 +1,9 @@ + + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/chromium-no-gpu b/chromium-no-gpu new file mode 100755 index 0000000..80eb7cc --- /dev/null +++ b/chromium-no-gpu @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +chromium --disable-gpu "$@"