Skip to content

Commit eeb61c1

Browse files
committed
Class for simulation result. Tracks were added to the result and no
longer as a listener. #2
1 parent 8e7f5e8 commit eeb61c1

14 files changed

+333
-262
lines changed

example/example.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import 'package:simdart/simdart.dart';
2+
import 'package:simdart/src/sim_result.dart';
23

34
void main() async {
4-
final SimDart sim = SimDart(onTrack: (track) => print(track));
5+
final SimDart sim = SimDart(includeTracks: true);
56

67
sim.process(event: _a, name: 'A');
78

8-
await sim.run(until: 10);
9+
SimResult result = await sim.run(until: 10);
10+
11+
result.tracks?.forEach((track) => print(track));
12+
print('startTime: ${result.startTime}');
13+
print('duration: ${result.duration}');
914
}
1015

1116
void _a(EventContext context) async {

lib/src/internal/event_action.dart

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class EventAction extends TimeAction implements EventContext {
1616
required String? eventName,
1717
required this.event,
1818
required this.resourceId,
19-
required this.onTrack,
2019
required this.onReject,
2120
required this.secondarySortByName})
2221
: _sim = sim,
@@ -26,10 +25,6 @@ class EventAction extends TimeAction implements EventContext {
2625
final String? _eventName;
2726
String get eventName => _eventName ?? hashCode.toString();
2827

29-
/// A callback function used to track the progress of the simulation.
30-
/// If provided, this function will be called with each [SimulationTrack] generated
31-
/// during the simulation. This is useful for debugging or logging purposes.
32-
final OnTrack? onTrack;
3328

3429
/// The event to be executed.
3530
final Event event;
@@ -62,10 +57,12 @@ class EventAction extends TimeAction implements EventContext {
6257
void execute() {
6358
final Function()? resume = _resume;
6459

60+
61+
6562
if (resume != null) {
66-
if (onTrack != null) {
67-
onTrack!(SimDartHelper.buildSimulationTrack(
68-
sim: _sim, eventName: eventName, status: Status.resumed));
63+
if (_sim.includeTracks) {
64+
SimDartHelper.addSimulationTrack(
65+
sim: _sim, eventName: eventName, status: Status.resumed);
6966
}
7067
// Resume the event if it is waiting, otherwise execute its action.
7168
resume.call();
@@ -78,13 +75,13 @@ class EventAction extends TimeAction implements EventContext {
7875
_resourceAcquired = resource.acquire(this);
7976
}
8077

81-
if (onTrack != null) {
78+
if (_sim.includeTracks) {
8279
Status status = Status.executed;
8380
if (!_canRun) {
8481
status = Status.rejected;
8582
}
86-
onTrack!(SimDartHelper.buildSimulationTrack(
87-
sim: _sim, eventName: eventName, status: status));
83+
SimDartHelper.addSimulationTrack(
84+
sim: _sim, eventName: eventName, status: status);
8885
}
8986

9087
if (_canRun) {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import 'package:meta/meta.dart';
2+
import 'package:simdart/src/execution_priority.dart';
3+
import 'package:simdart/src/start_time_handling.dart';
4+
5+
6+
@internal
7+
abstract interface class SimConfigurationInterface {
8+
/// Specifies how the simulation handles start times in the past.
9+
StartTimeHandling get startTimeHandling;
10+
11+
/// Defines the priority of task execution in the simulation.
12+
///
13+
/// - `highPriority`: Uses `Future.microtask` for immediate execution, prioritizing
14+
/// processing without blocking the UI.
15+
/// - `lowPriority`: Uses `Future.delayed(Duration.zero)` to ensure non-blocking
16+
/// execution, allowing the UI to remain responsive.
17+
ExecutionPriority get executionPriority;
18+
19+
/// Determines whether simulation tracks should be included in the simulation result.
20+
///
21+
/// When set to `true`, the simulation will collect and return a list of [SimulationTrack]
22+
/// objects as part of its result. If set to `false`, the tracks will not be collected,
23+
/// and the list will be `null`.
24+
///
25+
/// Default: `false`
26+
bool get includeTracks;
27+
28+
29+
30+
}

lib/src/internal/time_loop_interface.dart renamed to lib/src/internal/sim_result_interface.dart

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,8 @@
11
import 'package:meta/meta.dart';
2-
import 'package:simdart/src/execution_priority.dart';
3-
import 'package:simdart/src/internal/now_interface.dart';
4-
import 'package:simdart/src/start_time_handling.dart';
52

6-
/// Represents the temporal loop in the algorithm, managing the execution of actions at specified times.
3+
/// Represents the simulation result.
74
@internal
8-
abstract interface class TimeLoopInterface implements NowInterface {
9-
/// Specifies how the simulation handles start times in the past.
10-
StartTimeHandling get startTimeHandling;
11-
12-
/// Defines the priority of task execution in the simulation.
13-
///
14-
/// - `highPriority`: Uses `Future.microtask` for immediate execution, prioritizing
15-
/// processing without blocking the UI.
16-
/// - `lowPriority`: Uses `Future.delayed(Duration.zero)` to ensure non-blocking
17-
/// execution, allowing the UI to remain responsive.
18-
ExecutionPriority get executionPriority;
5+
abstract interface class SimResultInterface {
196

207
/// The time, in simulated time units, when the simulation started.
218
/// This is the moment at which the first event is scheduled to be processed.

lib/src/internal/time_loop.dart

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@ import 'dart:async';
33
import 'package:collection/collection.dart';
44
import 'package:meta/meta.dart';
55
import 'package:simdart/src/execution_priority.dart';
6+
import 'package:simdart/src/internal/now_interface.dart';
7+
import 'package:simdart/src/internal/sim_result_interface.dart';
68
import 'package:simdart/src/internal/time_action.dart';
7-
import 'package:simdart/src/internal/time_loop_interface.dart';
9+
import 'package:simdart/src/internal/sim_configuration_interface.dart';
10+
import 'package:simdart/src/sim_result.dart';
11+
import 'package:simdart/src/simulation_track.dart';
812
import 'package:simdart/src/start_time_handling.dart';
913

1014
/// Represents the temporal loop in the algorithm, managing the execution of actions at specified times.
1115
@internal
12-
class TimeLoop implements TimeLoopInterface {
16+
class TimeLoop implements SimConfigurationInterface,NowInterface,SimResultInterface {
1317
TimeLoop(
1418
{required int? now,
1519
required this.beforeRun,
20+
required this.includeTracks,
1621
required this.executionPriority,
1722
required this.startTimeHandling}) {
1823
_now = now ?? 0;
@@ -29,6 +34,9 @@ class TimeLoop implements TimeLoopInterface {
2934

3035
final Function beforeRun;
3136

37+
@override
38+
final bool includeTracks;
39+
3240
/// Queue that holds the [TimeAction] instances to be executed at their respective times.
3341
final PriorityQueue<TimeAction> _actions = PriorityQueue<TimeAction>(
3442
(a, b) {
@@ -58,22 +66,24 @@ class TimeLoop implements TimeLoopInterface {
5866
int get now => _now;
5967
late int _now;
6068

69+
List<SimulationTrack>? _tracks;
70+
6171
Completer<void>? _terminator;
6272

6373
/// Runs the simulation, processing actions in chronological order.
64-
Future<void> run({int? until}) async {
74+
Future<SimResult> run({int? until}) async {
6575
if (until != null && _now > until) {
6676
throw ArgumentError('`now` must be less than or equal to `until`.');
6777
}
6878
_until = until;
6979

7080
if (_terminator != null) {
71-
return;
81+
return _buildResult();
7282
}
7383
if (_actions.isEmpty) {
7484
_duration = 0;
7585
_startTime = 0;
76-
return;
86+
return _buildResult();
7787
}
7888
_duration = null;
7989
_startTime = null;
@@ -85,6 +95,11 @@ class TimeLoop implements TimeLoopInterface {
8595
await _terminator?.future;
8696
_duration = _now - (startTime ?? 0);
8797
_terminator = null;
98+
return _buildResult();
99+
}
100+
101+
SimResult _buildResult(){
102+
return SimResult(startTime: startTime, duration: duration, tracks: _tracks);
88103
}
89104

90105
void _scheduleNextEvent() {
@@ -105,6 +120,11 @@ class TimeLoop implements TimeLoopInterface {
105120
_actions.add(action);
106121
}
107122

123+
void addTrack(SimulationTrack track){
124+
_tracks ??= [];
125+
_tracks!.add(track);
126+
}
127+
108128
Future<void> _consumeFirstEvent() async {
109129
_nextEventScheduled = false;
110130
if (_actions.isEmpty) {

lib/src/sim_result.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import 'dart:collection';
2+
3+
import 'package:simdart/src/internal/sim_result_interface.dart';
4+
import 'package:simdart/src/simulation_track.dart';
5+
6+
class SimResult implements SimResultInterface {
7+
SimResult(
8+
{required this.duration,
9+
required this.startTime,
10+
required List<SimulationTrack>? tracks})
11+
: tracks = tracks != null ? UnmodifiableListView(tracks) : null;
12+
13+
@override
14+
final int? duration;
15+
16+
@override
17+
final int? startTime;
18+
19+
final UnmodifiableListView<SimulationTrack>? tracks;
20+
}

lib/src/simdart.dart

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@ import 'package:simdart/src/event.dart';
77
import 'package:simdart/src/execution_priority.dart';
88
import 'package:simdart/src/internal/event_action.dart';
99
import 'package:simdart/src/internal/event_scheduler_interface.dart';
10+
import 'package:simdart/src/internal/now_interface.dart';
1011
import 'package:simdart/src/internal/repeat_event_action.dart';
1112
import 'package:simdart/src/internal/resource.dart';
1213
import 'package:simdart/src/internal/time_action.dart';
1314
import 'package:simdart/src/internal/time_loop.dart';
14-
import 'package:simdart/src/internal/time_loop_interface.dart';
15+
import 'package:simdart/src/internal/sim_configuration_interface.dart';
1516
import 'package:simdart/src/interval.dart';
1617
import 'package:simdart/src/resource_configurator.dart';
18+
import 'package:simdart/src/sim_result.dart';
1719
import 'package:simdart/src/simulation_track.dart';
1820
import 'package:simdart/src/start_time_handling.dart';
1921

2022
/// Represents a discrete-event simulation engine.
21-
class SimDart implements TimeLoopInterface, EventSchedulerInterface {
23+
class SimDart implements SimConfigurationInterface, EventSchedulerInterface,NowInterface {
2224
/// Creates a simulation instance.
2325
///
2426
/// - [now]: The starting time of the simulation. Defaults to `0` if null.
@@ -27,8 +29,7 @@ class SimDart implements TimeLoopInterface, EventSchedulerInterface {
2729
/// - [startTimeHandling]: Determines how to handle events scheduled with a start
2830
/// time in the past. The default behavior is [StartTimeHandling.throwErrorIfPast].
2931
///
30-
/// - [onTrack]: The optional callback function that can be used to track the progress
31-
/// of the simulation.
32+
/// - [includeTracks]: Determines whether simulation tracks should be included in the simulation result.
3233
///
3334
/// - [seed]: The optional parameter used to initialize the random number generator
3435
/// for deterministic behavior in the simulation. If provided, it ensures that the
@@ -40,22 +41,25 @@ class SimDart implements TimeLoopInterface, EventSchedulerInterface {
4041
/// - [executionPriority]: Defines the priority of task execution in the simulation.
4142
SimDart(
4243
{StartTimeHandling startTimeHandling = StartTimeHandling.throwErrorIfPast,
43-
OnTrack? onTrack,
4444
int? now,
4545
this.secondarySortByName = false,
46+
this.includeTracks=false,
4647
ExecutionPriority executionPriority = ExecutionPriority.high,
4748
int? seed})
48-
: _onTrack = onTrack,
49-
random = Random(seed) {
49+
: random = Random(seed) {
5050
_loop = TimeLoop(
5151
now: now,
52+
includeTracks: includeTracks,
5253
beforeRun: _beforeRun,
5354
executionPriority: executionPriority,
5455
startTimeHandling: startTimeHandling);
5556
}
5657

5758
late final TimeLoop _loop;
5859

60+
@override
61+
final bool includeTracks;
62+
5963
/// Determines whether events with the same start time are sorted by their event name.
6064
///
6165
/// The primary sorting criterion is always the simulated start time (`start`). If
@@ -77,11 +81,6 @@ class SimDart implements TimeLoopInterface, EventSchedulerInterface {
7781
/// instantiate a new `Random` object for each event.
7882
late final Random random;
7983

80-
/// A callback function used to track the progress of the simulation.
81-
/// If provided, this function will be called with each [SimulationTrack] generated
82-
/// during the simulation. This is useful for debugging or logging purposes.
83-
final OnTrack? _onTrack;
84-
8584
/// A queue that holds event actions that are waiting for a resource to become available.
8685
///
8786
/// These events were initially denied the resource and are placed in this queue
@@ -101,7 +100,7 @@ class SimDart implements TimeLoopInterface, EventSchedulerInterface {
101100
///
102101
/// - [until]: The time at which execution should stop. Execution will include events
103102
/// scheduled at this time (inclusive). If null, execution will continue indefinitely.
104-
Future<void> run({int? until}) async {
103+
Future<SimResult> run({int? until}) async {
105104
return _loop.run(until: until);
106105
}
107106

@@ -190,7 +189,6 @@ class SimDart implements TimeLoopInterface, EventSchedulerInterface {
190189
} else {
191190
_loop.addAction(EventAction(
192191
sim: this,
193-
onTrack: _onTrack,
194192
start: start,
195193
eventName: name,
196194
event: event,
@@ -200,25 +198,17 @@ class SimDart implements TimeLoopInterface, EventSchedulerInterface {
200198
}
201199
}
202200

203-
@override
204-
int? get duration => _loop.duration;
205-
206201
@override
207202
ExecutionPriority get executionPriority => _loop.executionPriority;
208203

209204
@override
210205
int get now => _loop.now;
211206

212-
@override
213-
int? get startTime => _loop.startTime;
214207

215208
@override
216209
StartTimeHandling get startTimeHandling => _loop.startTimeHandling;
217210
}
218211

219-
/// A function signature for tracking the progress of a simulation.
220-
typedef OnTrack = void Function(SimulationTrack track);
221-
222212
/// Defines the behavior of the interval after a newly created event has been rejected.
223213
enum RejectedEventPolicy {
224214
/// Continues the repetition of the event at the specified intervals, even after the event was rejected.
@@ -275,18 +265,18 @@ class SimDartHelper {
275265
return sim._resources[resourceId];
276266
}
277267

278-
static SimulationTrack buildSimulationTrack(
268+
static void addSimulationTrack(
279269
{required SimDart sim,
280270
required String eventName,
281271
required Status status}) {
282272
Map<String, int> resourceUsage = {};
283273
for (Resource resource in sim._resources.values) {
284274
resourceUsage[resource.id] = resource.queue.length;
285275
}
286-
return SimulationTrack(
276+
sim._loop.addTrack(SimulationTrack(
287277
status: status,
288278
name: eventName,
289279
time: sim.now,
290-
resourceUsage: resourceUsage);
280+
resourceUsage: resourceUsage));
291281
}
292282
}

0 commit comments

Comments
 (0)