| // Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | /// This benchmark compares a large switch statement on various kinds of | 
 | /// values. The switch statement is part of a finite-state-machine (FSM) | 
 | /// recognizer. | 
 | /// | 
 | /// There are four copies of the same code, differing only by importing | 
 | /// different declarations of the type `State` which makes the same constant | 
 | /// names available using different types. | 
 | /// | 
 | /// The switch dispatch on the following types is benchmarked: | 
 | /// | 
 | ///   - a compact range of `int` values, | 
 | ///   - an enum, | 
 | ///   - a class that is a bit like an `enum` but not declared as an enum, | 
 | ///   - strings. | 
 | /// | 
 | /// The actual state-machine is somewhat aritificial. It recognizes a character | 
 | /// string of '0' and '1' character 'bits' that encode a valid UTF-8 string. The | 
 | /// state machine has 48 states and minimal logic in most states, so that as | 
 | /// much time as possible is executing the switch dispatch. | 
 | /// | 
 | /// The data is passed to the recogizer as a Uint8List to minimize the time to | 
 | /// access the bytes of the ASCII '0' / '1' character input sequence. | 
 |  | 
 | import 'dart:typed_data'; | 
 |  | 
 | import 'package:benchmark_harness/benchmark_harness.dart'; | 
 | import 'package:expect/expect.dart'; | 
 |  | 
 | import 'match_class.dart' as match_class; | 
 | import 'match_enum.dart' as match_enum; | 
 | import 'match_int.dart' as match_int; | 
 | import 'match_string.dart' as match_string; | 
 |  | 
 | class Benchmark extends BenchmarkBase { | 
 |   final bool Function(Uint8List) match; | 
 |  | 
 |   Benchmark(String kind, this.match) : super('SwitchFSM.$kind'); | 
 |  | 
 |   void validation() { | 
 |     void check(String s, bool expected) { | 
 |       Expect.equals(expected, match(convert(s)), '"$s"'); | 
 |     } | 
 |  | 
 |     check('', true); | 
 |     check('0', false); | 
 |     check('00', false); | 
 |     check('000', false); | 
 |     check('0000', false); | 
 |     check('00000', false); | 
 |     check('000000', false); | 
 |     check('0000000', false); | 
 |     check('00000000', true); | 
 |     check('01010101', true); | 
 |     check('10000000', false); | 
 |     check('001010101', false); | 
 |     check('11000000' '00000000', false); | 
 |     check('11000000' '10111111', true); | 
 |     check('11000000' '11111111', false); | 
 |     check('11100000' '00000000' '00000000', false); | 
 |     check('11100000' '10000000' '00000000', false); | 
 |     check('11100000' '10111111' '10111111', true); | 
 |     check('11110111' '10111111' '10111111' '01111111', false); | 
 |     check('11110111' '10111111' '10111111' '10111111', true); | 
 |     Expect.equals(testInputLength, testInput.length); | 
 |   } | 
 |  | 
 |   static const testInputLength = 1000; | 
 |   static final Uint8List testInput = convert(makeTestInput(testInputLength)); | 
 |  | 
 |   static String makeTestInput(int length) { | 
 |     // The test input uses most states of the FSM. It is repeated and padded to | 
 |     // make the length 1000. | 
 |     final testPattern = '' | 
 |         '11110111101111111011111110111111' | 
 |         '111011111011111110111111' | 
 |         '1101111110111111'; | 
 |     final paddingPattern = '00000000'; | 
 |     final repeats = testPattern * (length ~/ testPattern.length); | 
 |     final padding = | 
 |         paddingPattern * ((length - repeats.length) ~/ paddingPattern.length); | 
 |     return repeats + padding; | 
 |   } | 
 |  | 
 |   static Uint8List convert(String s) => Uint8List.fromList(s.codeUnits); | 
 |  | 
 |   @override | 
 |   void run() { | 
 |     Expect.equals(true, match(testInput)); | 
 |   } | 
 | } | 
 |  | 
 | enum SomeEnum { element } | 
 |  | 
 | void main() { | 
 |   // TODO(http://dartbug.com/51657): dart2js will remove `_Enum.index` in simple | 
 |   // programs that don't appear to use the field. This defeats the enum-switch | 
 |   // optimization that works more reliably in larger programs. Remove this code | 
 |   // that marks `_Enum.index` as used when #51657 is fixed. | 
 |   Expect.equals(0, SomeEnum.element.index); | 
 |  | 
 |   final benchmarks = [ | 
 |     Benchmark('enum', match_enum.match), | 
 |     Benchmark('int', match_int.match), | 
 |     Benchmark('class', match_class.match), | 
 |     Benchmark('string', match_string.match), | 
 |   ]; | 
 |  | 
 |   for (final benchmark in benchmarks) { | 
 |     benchmark.validation(); | 
 |   } | 
 |  | 
 |   for (final benchmark in benchmarks) { | 
 |     benchmark.warmup(); | 
 |   } | 
 |  | 
 |   for (final benchmark in benchmarks) { | 
 |     benchmark.report(); | 
 |   } | 
 | } |