diff --git a/protobuf/lib/src/protobuf/protobuf_enum.dart b/protobuf/lib/src/protobuf/protobuf_enum.dart index b96c119a..140febd7 100644 --- a/protobuf/lib/src/protobuf/protobuf_enum.dart +++ b/protobuf/lib/src/protobuf/protobuf_enum.dart @@ -2,21 +2,25 @@ // 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. +// ignore_for_file: non_constant_identifier_names + part of '../../protobuf.dart'; /// A base class for all proto enum types. /// -/// All proto `enum` classes inherit from [ProtobufEnum]. For example, given -/// the following enum defined in a proto file: +/// All proto `enum` classes inherit from [ProtobufEnum]. For example, given the +/// following enum defined in a proto file: /// -/// message MyMessage { -/// enum Color { -/// RED = 0; -/// GREEN = 1; -/// BLUE = 2; -/// }; -/// // ... -/// } +/// ``` +/// message MyMessage { +/// enum Color { +/// RED = 0; +/// GREEN = 1; +/// BLUE = 2; +/// }; +/// // ... +/// } +/// ``` /// /// the generated Dart file will include a `MyMessage_Color` class that extends /// `ProtobufEnum`. It will also include a `const MyMessage_Color` for each of @@ -37,16 +41,39 @@ class ProtobufEnum { /// Creates a new constant [ProtobufEnum] using [value] and [name]. const ProtobufEnum(this.value, this.name); - /// Creates a Map for all of the [ProtobufEnum]s in [byIndex], mapping each - /// [ProtobufEnum]'s [value] to the [ProtobufEnum]. - static Map initByValue(List byIndex) { - final byValue = {}; - for (final v in byIndex) { - byValue[v.value] = v; + /// @nodoc + static List $_initDenseList(List byIndex) { + if (byIndex.isEmpty) return []; + final byValue = List.filled(byIndex.last.value + 1, null); + for (final enumValue in byIndex) { + byValue[enumValue.value] = enumValue; } return byValue; } + /// @nodoc + static List $_initSparseList(List byIndex) => + byIndex.toList()..sort((e1, e2) => e1.value.compareTo(e2.value)); + + /// @nodoc + static T? $_binarySearch( + List sortedList, int value) { + var min = 0; + var max = sortedList.length; + while (min < max) { + final mid = min + ((max - min) >> 1); + final element = sortedList[mid]; + final comp = element.value.compareTo(value); + if (comp == 0) return element; + if (comp < 0) { + min = mid + 1; + } else { + max = mid; + } + } + return null; + } + /// Returns this enum's [name] or the [value] if names are not represented. @override String toString() => name == '' ? value.toString() : name; diff --git a/protoc_plugin/lib/protoc.dart b/protoc_plugin/lib/protoc.dart index e6d175bd..2ce0dd0a 100644 --- a/protoc_plugin/lib/protoc.dart +++ b/protoc_plugin/lib/protoc.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:collection/collection.dart'; import 'package:protobuf/protobuf.dart'; import 'const_generator.dart' show writeJsonConst; diff --git a/protoc_plugin/lib/src/enum_generator.dart b/protoc_plugin/lib/src/enum_generator.dart index a1cd8b5f..5dc6e40d 100644 --- a/protoc_plugin/lib/src/enum_generator.dart +++ b/protoc_plugin/lib/src/enum_generator.dart @@ -165,7 +165,6 @@ class EnumGenerator extends ProtobufContainer { } } out.println(); - out.println('static const $coreImportPrefix.List<$classname> values =' ' <$classname> ['); for (final val in _canonicalValues) { @@ -175,11 +174,31 @@ class EnumGenerator extends ProtobufContainer { out.println('];'); out.println(); - out.println( - 'static final $coreImportPrefix.Map<$coreImportPrefix.int, $classname> _byValue =' - ' $protobufImportPrefix.ProtobufEnum.initByValue(values);'); - out.println('static $classname? valueOf($coreImportPrefix.int value) =>' - ' _byValue[value];'); + var useList = _canonicalValues.isEmpty; + if (_canonicalValues.isNotEmpty) { + if (_canonicalValues.every((val) => !val.number.isNegative)) { + if (_canonicalValues.length / (_canonicalValues.last.number + 1) >= + 0.7) { + useList = true; + } + } + } + + if (useList) { + out.println( + 'static final $coreImportPrefix.List<$classname?> _byValue =' + ' $protobufImportPrefix.ProtobufEnum.\$_initDenseList(values);'); + + out.println('static $classname? valueOf($coreImportPrefix.int value) =>' + ' value < 0 || value >= _byValue.length ? null : _byValue[value];'); + } else { + out.println('static final $coreImportPrefix.List<$classname> _byValue =' + ' $protobufImportPrefix.ProtobufEnum.\$_initSparseList(values);'); + + out.println('static $classname? valueOf($coreImportPrefix.int value) =>' + ' $protobufImportPrefix.ProtobufEnum.\$_binarySearch(_byValue, value);'); + } + out.println(); out.println('const $classname._(super.v, super.n);'); diff --git a/protoc_plugin/lib/src/generated/descriptor.pbenum.dart b/protoc_plugin/lib/src/generated/descriptor.pbenum.dart index dc6f349d..e9000f81 100644 --- a/protoc_plugin/lib/src/generated/descriptor.pbenum.dart +++ b/protoc_plugin/lib/src/generated/descriptor.pbenum.dart @@ -88,9 +88,10 @@ class FieldDescriptorProto_Type extends $pb.ProtobufEnum { TYPE_SINT64, ]; - static final $core.Map<$core.int, FieldDescriptorProto_Type> _byValue = - $pb.ProtobufEnum.initByValue(values); - static FieldDescriptorProto_Type? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); + static FieldDescriptorProto_Type? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; const FieldDescriptorProto_Type._(super.v, super.n); } @@ -111,10 +112,10 @@ class FieldDescriptorProto_Label extends $pb.ProtobufEnum { LABEL_REPEATED, ]; - static final $core.Map<$core.int, FieldDescriptorProto_Label> _byValue = - $pb.ProtobufEnum.initByValue(values); + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); static FieldDescriptorProto_Label? valueOf($core.int value) => - _byValue[value]; + value < 0 || value >= _byValue.length ? null : _byValue[value]; const FieldDescriptorProto_Label._(super.v, super.n); } @@ -137,9 +138,10 @@ class FileOptions_OptimizeMode extends $pb.ProtobufEnum { LITE_RUNTIME, ]; - static final $core.Map<$core.int, FileOptions_OptimizeMode> _byValue = - $pb.ProtobufEnum.initByValue(values); - static FileOptions_OptimizeMode? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); + static FileOptions_OptimizeMode? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; const FileOptions_OptimizeMode._(super.v, super.n); } @@ -159,9 +161,10 @@ class FieldOptions_CType extends $pb.ProtobufEnum { STRING_PIECE, ]; - static final $core.Map<$core.int, FieldOptions_CType> _byValue = - $pb.ProtobufEnum.initByValue(values); - static FieldOptions_CType? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); + static FieldOptions_CType? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; const FieldOptions_CType._(super.v, super.n); } @@ -185,9 +188,10 @@ class FieldOptions_JSType extends $pb.ProtobufEnum { JS_NUMBER, ]; - static final $core.Map<$core.int, FieldOptions_JSType> _byValue = - $pb.ProtobufEnum.initByValue(values); - static FieldOptions_JSType? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); + static FieldOptions_JSType? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; const FieldOptions_JSType._(super.v, super.n); } @@ -212,10 +216,10 @@ class MethodOptions_IdempotencyLevel extends $pb.ProtobufEnum { IDEMPOTENT, ]; - static final $core.Map<$core.int, MethodOptions_IdempotencyLevel> _byValue = - $pb.ProtobufEnum.initByValue(values); + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); static MethodOptions_IdempotencyLevel? valueOf($core.int value) => - _byValue[value]; + value < 0 || value >= _byValue.length ? null : _byValue[value]; const MethodOptions_IdempotencyLevel._(super.v, super.n); } diff --git a/protoc_plugin/lib/src/generated/plugin.pbenum.dart b/protoc_plugin/lib/src/generated/plugin.pbenum.dart index 399158c5..23305393 100644 --- a/protoc_plugin/lib/src/generated/plugin.pbenum.dart +++ b/protoc_plugin/lib/src/generated/plugin.pbenum.dart @@ -27,10 +27,10 @@ class CodeGeneratorResponse_Feature extends $pb.ProtobufEnum { FEATURE_PROTO3_OPTIONAL, ]; - static final $core.Map<$core.int, CodeGeneratorResponse_Feature> _byValue = - $pb.ProtobufEnum.initByValue(values); + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); static CodeGeneratorResponse_Feature? valueOf($core.int value) => - _byValue[value]; + value < 0 || value >= _byValue.length ? null : _byValue[value]; const CodeGeneratorResponse_Feature._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/deprecations.pbenum b/protoc_plugin/test/goldens/deprecations.pbenum index 30bc5d78..3aa51f4b 100644 --- a/protoc_plugin/test/goldens/deprecations.pbenum +++ b/protoc_plugin/test/goldens/deprecations.pbenum @@ -24,9 +24,10 @@ class A extends $pb.ProtobufEnum { A2, ]; - static final $core.Map<$core.int, A> _byValue = - $pb.ProtobufEnum.initByValue(values); - static A? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); + static A? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; const A._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/doc_comments.pbenum b/protoc_plugin/test/goldens/doc_comments.pbenum index 7cde50e1..26e935f0 100644 --- a/protoc_plugin/test/goldens/doc_comments.pbenum +++ b/protoc_plugin/test/goldens/doc_comments.pbenum @@ -26,9 +26,10 @@ class A extends $pb.ProtobufEnum { A2, ]; - static final $core.Map<$core.int, A> _byValue = - $pb.ProtobufEnum.initByValue(values); - static A? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = + $pb.ProtobufEnum.$_initDenseList(values); + static A? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; const A._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/enum b/protoc_plugin/test/goldens/enum index 812247dd..aebc0cb5 100644 --- a/protoc_plugin/test/goldens/enum +++ b/protoc_plugin/test/goldens/enum @@ -11,8 +11,8 @@ class PhoneType extends $pb.ProtobufEnum { WORK, ]; - static final $core.Map<$core.int, PhoneType> _byValue = $pb.ProtobufEnum.initByValue(values); - static PhoneType? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = $pb.ProtobufEnum.$_initDenseList(values); + static PhoneType? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value]; const PhoneType._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/messageGeneratorEnums b/protoc_plugin/test/goldens/messageGeneratorEnums index 3469c7ba..4185223c 100644 --- a/protoc_plugin/test/goldens/messageGeneratorEnums +++ b/protoc_plugin/test/goldens/messageGeneratorEnums @@ -11,8 +11,8 @@ class PhoneNumber_PhoneType extends $pb.ProtobufEnum { WORK, ]; - static final $core.Map<$core.int, PhoneNumber_PhoneType> _byValue = $pb.ProtobufEnum.initByValue(values); - static PhoneNumber_PhoneType? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = $pb.ProtobufEnum.$_initDenseList(values); + static PhoneNumber_PhoneType? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value]; const PhoneNumber_PhoneType._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/topLevelEnum.pbenum b/protoc_plugin/test/goldens/topLevelEnum.pbenum index 30d81a24..5b944361 100644 --- a/protoc_plugin/test/goldens/topLevelEnum.pbenum +++ b/protoc_plugin/test/goldens/topLevelEnum.pbenum @@ -26,8 +26,8 @@ class PhoneType extends $pb.ProtobufEnum { WORK, ]; - static final $core.Map<$core.int, PhoneType> _byValue = $pb.ProtobufEnum.initByValue(values); - static PhoneType? valueOf($core.int value) => _byValue[value]; + static final $core.List _byValue = $pb.ProtobufEnum.$_initDenseList(values); + static PhoneType? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value]; const PhoneType._(super.v, super.n); }