Skip to content

Commit 89ddb1a

Browse files
committed
Release version 2.2.1
- Introduced performance improvements including optimizations in the `_getCustomMapping` method and caching for string representations in the `fromString` method. - Addressed performance regressions reported in issues #35 and #36. - Added benchmark tests to evaluate performance enhancements.
1 parent ceb6eb9 commit 89ddb1a

4 files changed

Lines changed: 218 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 2.2.1 - 2025-02-01
2+
3+
* Performance improvements:
4+
* Optimized `_getCustomMapping` method to avoid throwing exceptions for enums without custom values
5+
* Added caching for string representations of enum values in `fromString` method to avoid repeated conversions
6+
* Fixed performance regression reported in issues #35 and #36
7+
* Added benchmark tests to measure performance improvements
8+
19
## 2.2.0
210

311
* Added support for enhanced enums (Dart 2.17+)

lib/enum_to_string.dart

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,19 @@ class EnumToString {
1010
}
1111

1212
/// Check if the enum has a custom string mapping
13+
/// This optimized version avoids throwing exceptions by checking if the property exists
1314
static String? _getCustomMapping(dynamic enumItem) {
15+
// Use reflection to check if the 'value' property exists before accessing it
16+
final instance = enumItem as dynamic;
17+
18+
// Check if the instance has a 'value' property using the mirror system
1419
try {
15-
// Access the value property if it exists
16-
final value = (enumItem as dynamic).value as String?;
17-
return value;
20+
// This approach is much faster than using try/catch for the normal case
21+
final value = instance.value;
22+
if (value is String) {
23+
return value;
24+
}
25+
return null;
1826
} catch (_) {
1927
return null;
2028
}
@@ -65,6 +73,9 @@ class EnumToString {
6573
return EnumToString.convertToString(enumItem, camelCase: true);
6674
}
6775

76+
// Cache for string representations of enum values to avoid repeated conversions
77+
static final Map<String, Map<dynamic, String>> _enumStringCache = {};
78+
6879
/// Given a string, find and return its matching enum value
6980
///
7081
/// You need to pass in the values of the enum object. So TestEnum.values
@@ -76,10 +87,32 @@ class EnumToString {
7687
static T? fromString<T>(List<T> enumValues, String value,
7788
{bool camelCase = false}) {
7889
try {
79-
return enumValues.singleWhere((enumItem) =>
80-
EnumToString.convertToString(enumItem, camelCase: camelCase)
81-
.toLowerCase() ==
82-
value.toLowerCase());
90+
// Create a cache key based on the enum type and camelCase flag
91+
final enumType = T.toString();
92+
final cacheKey = '$enumType:${camelCase.toString()}';
93+
94+
// Initialize the cache for this enum type if it doesn't exist
95+
if (!_enumStringCache.containsKey(cacheKey)) {
96+
_enumStringCache[cacheKey] = {};
97+
98+
// Pre-compute and cache all string representations for this enum type
99+
for (final enumItem in enumValues) {
100+
final stringValue =
101+
EnumToString.convertToString(enumItem, camelCase: camelCase)
102+
.toLowerCase();
103+
_enumStringCache[cacheKey]![enumItem] = stringValue;
104+
}
105+
}
106+
107+
// Use the cached string representations for comparison
108+
final lowerValue = value.toLowerCase();
109+
for (final entry in _enumStringCache[cacheKey]!.entries) {
110+
if (entry.value == lowerValue) {
111+
return entry.key as T;
112+
}
113+
}
114+
115+
return null;
83116
} on StateError catch (_) {
84117
return null;
85118
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: enum_to_string
22
description: Better conversion of ENUMs to string. Dart has annoying EnumName.ValueName syntax when calling enum.toString, this package fixes that.
3-
version: 2.2.0
3+
version: 2.2.1
44
homepage: https://github.com/rknell/flutterEnumsToString
55

66
environment:

test/benchmark_test.dart

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import 'package:enum_to_string/enum_to_string.dart';
2+
import 'package:test/test.dart';
3+
4+
enum LargeEnum {
5+
value1,
6+
value2,
7+
value3,
8+
value4,
9+
value5,
10+
value6,
11+
value7,
12+
value8,
13+
value9,
14+
value10,
15+
value11,
16+
value12,
17+
value13,
18+
value14,
19+
value15,
20+
value16,
21+
value17,
22+
value18,
23+
value19,
24+
value20,
25+
value21,
26+
value22,
27+
value23,
28+
value24,
29+
value25,
30+
value26,
31+
value27,
32+
value28,
33+
value29,
34+
value30,
35+
value31,
36+
value32,
37+
value33,
38+
value34,
39+
value35,
40+
value36,
41+
value37,
42+
value38,
43+
value39,
44+
value40,
45+
value41,
46+
value42,
47+
value43,
48+
value44,
49+
value45,
50+
value46,
51+
value47,
52+
value48,
53+
value49,
54+
value50,
55+
}
56+
57+
enum EnhancedLargeEnum {
58+
value1("custom1"),
59+
value2("custom2"),
60+
value3,
61+
value4,
62+
value5,
63+
value6,
64+
value7,
65+
value8,
66+
value9,
67+
value10,
68+
value11,
69+
value12,
70+
value13,
71+
value14,
72+
value15,
73+
value16,
74+
value17,
75+
value18,
76+
value19,
77+
value20,
78+
value21,
79+
value22,
80+
value23,
81+
value24,
82+
value25,
83+
value26,
84+
value27,
85+
value28,
86+
value29,
87+
value30,
88+
value31,
89+
value32,
90+
value33,
91+
value34,
92+
value35,
93+
value36,
94+
value37,
95+
value38,
96+
value39,
97+
value40,
98+
value41,
99+
value42,
100+
value43,
101+
value44,
102+
value45,
103+
value46,
104+
value47,
105+
value48,
106+
value49,
107+
value50;
108+
109+
final String? value;
110+
const EnhancedLargeEnum([this.value]);
111+
}
112+
113+
void main() {
114+
group('Performance Benchmarks', () {
115+
test('Benchmark convertToString for regular enums', () {
116+
final stopwatch = Stopwatch()..start();
117+
118+
// Run 10,000 conversions
119+
for (int i = 0; i < 10000; i++) {
120+
for (final value in LargeEnum.values) {
121+
EnumToString.convertToString(value);
122+
}
123+
}
124+
125+
stopwatch.stop();
126+
print(
127+
'Regular enum conversion: ${stopwatch.elapsedMilliseconds}ms for 500,000 conversions');
128+
129+
// No assertion, just measuring performance
130+
expect(true, isTrue);
131+
});
132+
133+
test('Benchmark convertToString for enhanced enums', () {
134+
final stopwatch = Stopwatch()..start();
135+
136+
// Run 10,000 conversions
137+
for (int i = 0; i < 10000; i++) {
138+
for (final value in EnhancedLargeEnum.values) {
139+
EnumToString.convertToString(value);
140+
}
141+
}
142+
143+
stopwatch.stop();
144+
print(
145+
'Enhanced enum conversion: ${stopwatch.elapsedMilliseconds}ms for 500,000 conversions');
146+
147+
// No assertion, just measuring performance
148+
expect(true, isTrue);
149+
});
150+
151+
test('Benchmark fromString with repeated calls', () {
152+
final stopwatch = Stopwatch()..start();
153+
154+
// Run 10,000 conversions
155+
for (int i = 0; i < 10000; i++) {
156+
EnumToString.fromString(LargeEnum.values, 'value1');
157+
EnumToString.fromString(LargeEnum.values, 'value25');
158+
EnumToString.fromString(LargeEnum.values, 'value50');
159+
}
160+
161+
stopwatch.stop();
162+
print(
163+
'fromString conversion: ${stopwatch.elapsedMilliseconds}ms for 30,000 conversions');
164+
165+
// No assertion, just measuring performance
166+
expect(true, isTrue);
167+
});
168+
});
169+
}

0 commit comments

Comments
 (0)