88// of patent rights can be found in the PATENTS file in the same directory.
99//
1010
11- #import " ASLayoutSpec.h"
11+ #import " ASLayoutSpec+Private .h"
1212
1313#import " ASAssert.h"
1414#import " ASEnvironmentInternal.h"
1717#import " ASThread.h"
1818#import " ASTraitCollection.h"
1919
20- #import < objc/runtime.h>
21- #import < map>
2220#import < vector>
2321
24- typedef std::map<unsigned long , id <ASLayoutable>, std::less<unsigned long >> ASChildMap;
25-
2622@interface ASLayoutSpec () {
2723 ASEnvironmentState _environmentState;
2824 ASDN::RecursiveMutex __instanceLock__;
29- ASChildMap _children;
25+ ASChildrenMap _childrenMap;
26+ unsigned long _mutations;
3027}
3128@end
3229
@@ -35,6 +32,7 @@ @implementation ASLayoutSpec
3532// these dynamic properties all defined in ASLayoutOptionsPrivate.m
3633@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis,
3734 alignSelf, ascender, descender, sizeRange, layoutPosition, layoutableType;
35+ @synthesize parent = _parent;
3836@synthesize isFinalLayoutable = _isFinalLayoutable;
3937
4038- (instancetype )init
@@ -44,6 +42,7 @@ - (instancetype)init
4442 }
4543 _isMutable = YES ;
4644 _environmentState = ASEnvironmentStateMakeDefault ();
45+ _mutations = 0 ;
4746 return self;
4847}
4948
@@ -105,6 +104,8 @@ - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
105104 return child;
106105}
107106
107+ #pragma mark - Parent
108+
108109- (void )setParent : (id <ASLayoutable>)parent
109110{
110111 // FIXME: Locking should be evaluated here. _parent is not widely used yet, though.
@@ -115,30 +116,33 @@ - (void)setParent:(id<ASLayoutable>)parent
115116 }
116117}
117118
119+ - (id <ASLayoutable>)parent
120+ {
121+ return _parent;
122+ }
123+
124+ #pragma mark - Children
125+
118126- (void )setChild : (id <ASLayoutable>)child
119127{
120- ASDisplayNodeAssert (self.isMutable , @" Cannot set properties when layout spec is not mutable" );
121- if (child) {
122- id <ASLayoutable> finalLayoutable = [self layoutableToAddFromLayoutable: child];
123- if (finalLayoutable) {
124- _children[0 ] = finalLayoutable;
125- [self propagateUpLayoutable: finalLayoutable];
126- }
127- } else {
128- _children.erase (0 );
129- }
128+ [self setChild: child forIndex: 0 ];
130129}
131130
132131- (void )setChild : (id <ASLayoutable>)child forIndex : (NSUInteger )index
133132{
134133 ASDisplayNodeAssert (self.isMutable , @" Cannot set properties when layout spec is not mutable" );
135134 if (child) {
136135 id <ASLayoutable> finalLayoutable = [self layoutableToAddFromLayoutable: child];
137- _children[index] = finalLayoutable;
136+ if (finalLayoutable) {
137+ _childrenMap[index] = finalLayoutable;
138+ [self propagateUpLayoutable: finalLayoutable];
139+ }
138140 } else {
139- _children .erase (index);
141+ _childrenMap .erase (index);
140142 }
141- // TODO: Should we propagate up the layoutable at it could happen that multiple children will propagated up their
143+ _mutations++;
144+
145+ // TODO: Should we propagate up the layoutable as it could happen that multiple children will propagated up their
142146 // layout options and one child will overwrite values from another child
143147 // [self propagateUpLayoutable:finalLayoutable];
144148}
@@ -147,37 +151,73 @@ - (void)setChildren:(NSArray<id<ASLayoutable>> *)children
147151{
148152 ASDisplayNodeAssert (self.isMutable , @" Cannot set properties when layout spec is not mutable" );
149153
150- _children .clear ();
154+ _childrenMap .clear ();
151155 NSUInteger i = 0 ;
152156 for (id <ASLayoutable> child in children) {
153- _children [i] = [self layoutableToAddFromLayoutable: child];
157+ _childrenMap [i] = [self layoutableToAddFromLayoutable: child];
154158 i += 1 ;
159+
160+ _mutations++;
155161 }
156162}
157163
158164- (id <ASLayoutable>)childForIndex : (NSUInteger )index
159165{
160- if (index < _children .size ()) {
161- return _children [index];
166+ if (index < _childrenMap .size ()) {
167+ return _childrenMap [index];
162168 }
163169 return nil ;
164170}
165171
166172- (id <ASLayoutable>)child
167173{
168- return _children [0 ];
174+ return _childrenMap [0 ];
169175}
170176
171177- (NSArray *)children
172178{
179+ // If used inside ASDK, the childrenMap property should be preferred over the children array to prevent
180+ // unecessary boxing
173181 std::vector<ASLayout *> children;
174- for (ASChildMap::iterator it = _children. begin (); it != _children. end (); ++it ) {
175- children.push_back (it-> second );
182+ for (auto const &entry : _childrenMap ) {
183+ children.push_back (entry. second );
176184 }
177-
185+
178186 return [NSArray arrayWithObjects: &children[0 ] count: children.size ()];
179187}
180188
189+ #pragma mark - NSFastEnumeration
190+
191+ - (NSUInteger )countByEnumeratingWithState : (NSFastEnumerationState *)state
192+ objects : (id __unsafe_unretained [])stackbuf
193+ count : (NSUInteger )stackbufLength
194+ {
195+ NSUInteger count = 0 ;
196+ unsigned long countOfItemsAlreadyEnumerated = state->state ;
197+
198+ if (countOfItemsAlreadyEnumerated == 0 ) {
199+ state->mutationsPtr = &_mutations;
200+ }
201+
202+ if (countOfItemsAlreadyEnumerated < _childrenMap.size ()) {
203+ state->itemsPtr = stackbuf;
204+
205+ while ((countOfItemsAlreadyEnumerated < _childrenMap.size ()) && (count < stackbufLength)) {
206+ // Hold on for the object while enumerating
207+ __autoreleasing id child = _childrenMap[countOfItemsAlreadyEnumerated];
208+ stackbuf[count] = child;
209+ countOfItemsAlreadyEnumerated++;
210+ count++;
211+ }
212+ } else {
213+ count = 0 ;
214+ }
215+
216+ state->state = countOfItemsAlreadyEnumerated;
217+
218+ return count;
219+ }
220+
181221#pragma mark - ASEnvironment
182222
183223- (ASEnvironmentState)environmentState
@@ -233,6 +273,15 @@ - (ASTraitCollection *)asyncTraitCollection
233273
234274@end
235275
276+ @implementation ASLayoutSpec (Private)
277+
278+ - (ASChildrenMap)childrenMap
279+ {
280+ return _childrenMap;
281+ }
282+
283+ @end
284+
236285@implementation ASLayoutSpec (Debugging)
237286
238287#pragma mark - ASLayoutableAsciiArtProtocol
0 commit comments