roi peker

optimize GetBuilder "group id" using `HashSet`

- `Changed HashMap<int,GetStateUpdate>` to `HashSet<GetStateUpdate>`.
 Reference https://github.com/jonataslaw/getx/pull/565#discussion_r484088390
-  Added a internal VoidCallback in `GetStateUpdaterMixin::getUpdate`, to see if it reduces overhead of anonym function in `setState()` (considering GC).
@@ -12,7 +12,9 @@ import 'simple_builder.dart'; @@ -12,7 +12,9 @@ import 'simple_builder.dart';
12 //typedef Disposer = void Function(); 12 //typedef Disposer = void Function();
13 13
14 // replacing StateSetter, return if the Widget is mounted for extra validation. 14 // replacing StateSetter, return if the Widget is mounted for extra validation.
  15 +// if it brings overhead the extra call,
15 typedef GetStateUpdate = bool Function(); 16 typedef GetStateUpdate = bool Function();
  17 +//typedef GetStateUpdate = void Function(VoidCallback fn);
16 18
17 /// Complies with [GetStateUpdater] 19 /// Complies with [GetStateUpdater]
18 /// 20 ///
@@ -24,9 +26,14 @@ typedef GetStateUpdate = bool Function(); @@ -24,9 +26,14 @@ typedef GetStateUpdate = bool Function();
24 /// TODO: check performance HIT for the extra method call. 26 /// TODO: check performance HIT for the extra method call.
25 /// 27 ///
26 mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> { 28 mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> {
  29 + // To avoid the creation of an anonym function to be GC later.
  30 + static VoidCallback _stateCallback = () {};
  31 +
  32 + /// Experimental method to replace setState((){});
  33 + /// Used with GetStateUpdate.
27 bool getUpdate() { 34 bool getUpdate() {
28 final _mounted = mounted; 35 final _mounted = mounted;
29 - if (_mounted) setState(() {}); 36 + if (_mounted) setState(_stateCallback);
30 return _mounted; 37 return _mounted;
31 } 38 }
32 } 39 }
@@ -37,10 +44,7 @@ class GetxController extends DisposableInterface { @@ -37,10 +44,7 @@ class GetxController extends DisposableInterface {
37 // final _updatersIds = HashMap<String, StateSetter>(); //<old> 44 // final _updatersIds = HashMap<String, StateSetter>(); //<old>
38 final _updatersIds = HashMap<String, GetStateUpdate>(); 45 final _updatersIds = HashMap<String, GetStateUpdate>();
39 46
40 -// final _updatersGroupIds = HashMap<String, List>(); //<old>  
41 - final _updatersGroupIds = HashMap<String, HashMap<int, GetStateUpdate>>();  
42 -  
43 - static int _groupIdCount = 0; 47 + final _updatersGroupIds = HashMap<String, HashSet<GetStateUpdate>>();
44 48
45 /// Rebuilds [GetBuilder] each time you call [update()]; 49 /// Rebuilds [GetBuilder] each time you call [update()];
46 /// Can take a List of [ids], that will only update the matching 50 /// Can take a List of [ids], that will only update the matching
@@ -50,14 +54,21 @@ class GetxController extends DisposableInterface { @@ -50,14 +54,21 @@ class GetxController extends DisposableInterface {
50 void update([List<String> ids, bool condition = true]) { 54 void update([List<String> ids, bool condition = true]) {
51 if (!condition) return; 55 if (!condition) return;
52 if (ids == null) { 56 if (ids == null) {
53 -// _updaters.forEach((rs) => rs(() {}));//<old> 57 +// _updaters?.forEach((rs) => rs(() {})); //<old>
54 _updaters.forEach((rs) => rs()); 58 _updaters.forEach((rs) => rs());
55 } else { 59 } else {
56 - ids.forEach((element) {  
57 -// _updatersGroupIds[element]?.forEach((k, rs) => rs(() {}));//<old>  
58 -// _updatersIds[element]?.call(() {});//<old>  
59 - _updatersIds[element]?.call();  
60 - _updatersGroupIds[element]?.forEach((k, rs) => rs()); 60 + // @jonny, remove this commented code if it's not more optimized.
  61 +// for (final id in ids) {
  62 +// if (_updatersIds[id] != null) _updatersIds[id]();
  63 +// if (_updatersGroupIds[id] != null)
  64 +// for (final rs in _updatersGroupIds[id]) rs();
  65 +// }
  66 +
  67 + ids.forEach((id) {
  68 +// _updatersIds[id]?.call(() {}); //<old>
  69 +// _updatersGroupIds[id]?.forEach((rs) => rs(() {})); //<old>
  70 + _updatersIds[id]?.call();
  71 + _updatersGroupIds[id]?.forEach((rs) => rs());
61 }); 72 });
62 } 73 }
63 } 74 }
@@ -72,13 +83,10 @@ class GetxController extends DisposableInterface { @@ -72,13 +83,10 @@ class GetxController extends DisposableInterface {
72 VoidCallback addListenerId(String key, GetStateUpdate listener) { 83 VoidCallback addListenerId(String key, GetStateUpdate listener) {
73 // _printCurrentIds(); 84 // _printCurrentIds();
74 if (_updatersIds.containsKey(key)) { 85 if (_updatersIds.containsKey(key)) {
75 - final _innerKey = _groupIdCount++;  
76 -// final _ref = _updatersGroupIds[key] ??= HashMap<int, StateSetter>();//<old>  
77 - final _ref = _updatersGroupIds[key] ??= HashMap<int, GetStateUpdate>();  
78 - _ref[_innerKey] = listener; 86 + _updatersGroupIds[key] ??= HashSet<GetStateUpdate>.identity();
  87 + _updatersGroupIds[key].add(listener);
79 return () { 88 return () {
80 - _ref?.remove(_innerKey);  
81 -// _printCurrentIds(); 89 + _updatersGroupIds[key].remove(listener);
82 }; 90 };
83 } else { 91 } else {
84 _updatersIds[key] = listener; 92 _updatersIds[key] = listener;
@@ -148,10 +156,6 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> @@ -148,10 +156,6 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
148 with GetStateUpdaterMixin { 156 with GetStateUpdaterMixin {
149 GetxController controller; 157 GetxController controller;
150 bool isCreator = false; 158 bool isCreator = false;
151 -  
152 - /// TODO: @jonny, you intend to use disposers?  
153 -// final HashSet<Disposer> disposers = HashSet<Disposer>();  
154 -  
155 VoidCallback remove; 159 VoidCallback remove;
156 160
157 @override 161 @override
@@ -195,8 +199,8 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> @@ -195,8 +199,8 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
195 void _subscribeToController() { 199 void _subscribeToController() {
196 remove?.call(); 200 remove?.call();
197 remove = (widget.id == null) 201 remove = (widget.id == null)
198 -// ? controller?.addListener(setState)//<old>  
199 -// : controller?.addListenerId(widget.id, setState);//<old> 202 +// ? controller?.addListener(setState) //<old>
  203 +// : controller?.addListenerId(widget.id, setState); //<old>
200 ? controller?.addListener(getUpdate) 204 ? controller?.addListener(getUpdate)
201 : controller?.addListenerId(widget.id, getUpdate); 205 : controller?.addListenerId(widget.id, getUpdate);
202 } 206 }
@@ -218,10 +222,6 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> @@ -218,10 +222,6 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
218 } 222 }
219 } 223 }
220 remove?.call(); 224 remove?.call();
221 -  
222 -// disposers.forEach((element) {  
223 -// element();  
224 -// });  
225 } 225 }
226 226
227 @override 227 @override
@@ -251,6 +251,7 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> @@ -251,6 +251,7 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
251 /// like Rx() does with Obx(). 251 /// like Rx() does with Obx().
252 class Value<T> extends GetxController { 252 class Value<T> extends GetxController {
253 Value([this._value]); 253 Value([this._value]);
  254 +
254 T _value; 255 T _value;
255 256
256 T get value { 257 T get value {