• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_ITEM_GROUP_LAYOUT_ALGORITHM_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_ITEM_GROUP_LAYOUT_ALGORITHM_H
18 
19 #include <optional>
20 #include "base/geometry/axis.h"
21 #include "core/components_ng/layout/layout_algorithm.h"
22 #include "core/components_ng/layout/layout_wrapper.h"
23 #include "core/components_ng/pattern/list/list_layout_property.h"
24 #include "core/components_v2/list/list_properties.h"
25 
26 namespace OHOS::Ace::NG {
27 class ListPositionMap;
28 class ListChildrenMainSize;
29 struct ListItemGroupLayoutInfo;
30 struct LayoutedItemInfo {
31     int32_t startIndex = 0;
32     float startPos = 0.0f;
33     int32_t endIndex = 0;
34     float endPos = 0.0f;
35 };
36 
37 struct ListItemGroupInfo {
38     int32_t id = -1;
39     float startPos = 0.0f;
40     float endPos = 0.0f;
41     bool isPressed = false;
42 };
43 
44 struct ListItemGroupCacheParam {
45     bool forward = true;
46     bool backward = false;
47     bool show = false;
48     int32_t cacheCountForward = 0;
49     int32_t cacheCountBackward = 0;
50     int32_t forwardCachedIndex = -1;
51     int32_t backwardCachedIndex = INT_MAX;
52     int64_t deadline = 0;
53 };
54 
55 struct CachedIndexInfo {
56     int32_t forwardCachedCount = 0;
57     int32_t backwardCachedCount = 0;
58     int32_t forwardCacheMax = 0;
59     int32_t backwardCacheMax = 0;
60 };
61 
62 // TextLayoutAlgorithm acts as the underlying text layout.
63 class ACE_EXPORT ListItemGroupLayoutAlgorithm : public LayoutAlgorithm {
64     DECLARE_ACE_TYPE(ListItemGroupLayoutAlgorithm, LayoutAlgorithm);
65 public:
66     using PositionMap = std::map<int32_t, ListItemGroupInfo>;
67 
68     static const int32_t LAST_ITEM = -1;
69 
70     ListItemGroupLayoutAlgorithm(int32_t headerIndex, int32_t footerIndex, int32_t itemStartIndex,
71         int32_t footerCount = 0)
headerIndex_(headerIndex)72         : headerIndex_(headerIndex), footerIndex_(footerIndex), itemStartIndex_(itemStartIndex),
73           footerCount_(footerCount)
74     {}
75 
76     void Measure(LayoutWrapper* layoutWrapper) override;
77 
78     void Layout(LayoutWrapper* layoutWrapper) override;
79 
GetItemPosition()80     const PositionMap& GetItemPosition() const
81     {
82         return itemPosition_;
83     }
84 
GetCachedItemPosition()85     const PositionMap& GetCachedItemPosition() const
86     {
87         return cachedItemPosition_;
88     }
89 
ResetCachedItemPosition()90     void ResetCachedItemPosition()
91     {
92         cachedItemPosition_.clear();
93     }
94 
ResetCachedIndex()95     void ResetCachedIndex()
96     {
97         forwardCachedIndex_ = -1;
98         backwardCachedIndex_ = INT_MAX;
99     }
100 
SetItemsPosition(const PositionMap & itemPosition)101     void SetItemsPosition(const PositionMap& itemPosition)
102     {
103         itemPosition_ = itemPosition;
104     }
105 
SetCachedItemsPosition(const PositionMap & itemPosition)106     void SetCachedItemsPosition(const PositionMap& itemPosition)
107     {
108         cachedItemPosition_ = itemPosition;
109     }
110 
111     void ClearItemPosition();
112 
GetSpaceWidth()113     float GetSpaceWidth() const
114     {
115         return spaceWidth_;
116     }
117 
GetAxis()118     Axis GetAxis() const
119     {
120         return axis_;
121     }
122 
GetLayoutDirection()123     TextDirection GetLayoutDirection() const
124     {
125         return layoutDirection_;
126     }
127 
GetMainSize()128     float GetMainSize() const
129     {
130         return totalMainSize_;
131     }
132 
GetLanes()133     int32_t GetLanes() const
134     {
135         return lanes_;
136     }
137 
GetLaneGutter()138     float GetLaneGutter() const
139     {
140         return laneGutter_;
141     }
142 
GetLanesFloor(int32_t index)143     int32_t GetLanesFloor(int32_t index) const
144     {
145         if (lanes_ <= 1) {
146             return index;
147         }
148         return index - index % lanes_;
149     }
150 
GetLanesCeil(int32_t index)151     int32_t GetLanesCeil(int32_t index) const
152     {
153         int32_t tmpIndex = (lanes_ <= 1) ? index : (index - index % lanes_ + lanes_ - 1);
154         tmpIndex = tmpIndex >= totalItemCount_ ? totalItemCount_ - 1 : tmpIndex;
155         return tmpIndex;
156     }
157 
SetListMainSize(float startPos,float endPos,float referencePos,float prevContentSize,bool forwardLayout)158     void SetListMainSize(float startPos, float endPos, float referencePos, float prevContentSize, bool forwardLayout)
159     {
160         startPos_ = startPos;
161         endPos_ = endPos;
162         referencePos_ = referencePos;
163         forwardLayout_ = forwardLayout;
164         refPos_ = referencePos;
165         prevContentMainSize_ = prevContentSize;
166     }
167 
GetListContentSize()168     float GetListContentSize() const
169     {
170         return endPos_ - startPos_;
171     }
172 
173     void ModifyReferencePos(int32_t index, float pos);
174 
SetNeedAdjustRefPos(bool needAdjust)175     void SetNeedAdjustRefPos(bool needAdjust)
176     {
177         needAdjustRefPos_ = needAdjust;
178     }
179 
SetNeedCheckOffset(bool needCheckOffset,float averageHeight)180     void SetNeedCheckOffset(bool needCheckOffset, float averageHeight)
181     {
182         isNeedCheckOffset_ = needCheckOffset;
183         groupItemAverageHeight_ = averageHeight;
184     }
185 
GetRefPos()186     float GetRefPos() const
187     {
188         return refPos_;
189     }
190 
SetContentOffset(float contentStartOffset,float contentEndOffset)191     void SetContentOffset(float contentStartOffset, float contentEndOffset)
192     {
193         contentStartOffset_ = contentStartOffset;
194         contentEndOffset_ = contentEndOffset;
195     }
196 
SetListLayoutProperty(RefPtr<ListLayoutProperty> layoutProperty)197     void SetListLayoutProperty(RefPtr<ListLayoutProperty> layoutProperty)
198     {
199         listLayoutProperty_ = std::move(layoutProperty);
200     }
201 
SetJumpIndex(int32_t index)202     void SetJumpIndex(int32_t index)
203     {
204         jumpIndex_ = index;
205     }
206 
SetTargetIndex(int32_t index)207     void SetTargetIndex(int32_t index)
208     {
209         targetIndex_ = index;
210     }
211 
GetStartIndex()212     int32_t GetStartIndex() const
213     {
214         return itemPosition_.empty() ? 0 : itemPosition_.begin()->first;
215     }
216 
GetEndIndex()217     int32_t GetEndIndex() const
218     {
219         return itemPosition_.empty() ? 0 : itemPosition_.rbegin()->first;
220     }
221 
GetCacheStartIndex()222     int32_t GetCacheStartIndex() const
223     {
224         return cachedItemPosition_.empty() ? -1 : cachedItemPosition_.begin()->first;
225     }
226 
GetCacheEndIndex()227     int32_t GetCacheEndIndex() const
228     {
229         return cachedItemPosition_.empty() ? -1 : cachedItemPosition_.rbegin()->first;
230     }
231 
GetStartPosition()232     float GetStartPosition() const
233     {
234         if (itemPosition_.empty()) {
235             return 0.0f;
236         }
237         if (GetStartIndex() == 0) {
238             return itemPosition_.begin()->second.startPos;
239         }
240         return itemPosition_.begin()->second.startPos - spaceWidth_;
241     }
242 
GetEndPosition()243     float GetEndPosition() const
244     {
245         if (itemPosition_.empty()) {
246             return 0.0f;
247         }
248         if (GetEndIndex() == totalItemCount_ - 1) {
249             return itemPosition_.rbegin()->second.endPos;
250         }
251         return itemPosition_.rbegin()->second.endPos + spaceWidth_;
252     }
253 
GetCacheStartPosition()254     float GetCacheStartPosition() const
255     {
256         if (cachedItemPosition_.empty()) {
257             return 0.0f;
258         }
259         if (GetCacheStartIndex() == 0) {
260             return cachedItemPosition_.begin()->second.startPos;
261         }
262         return cachedItemPosition_.begin()->second.startPos - spaceWidth_;
263     }
264 
GetCacheEndPosition()265     float GetCacheEndPosition() const
266     {
267         if (cachedItemPosition_.empty()) {
268             return 0.0f;
269         }
270         if (GetCacheEndIndex() == totalItemCount_ - 1) {
271             return cachedItemPosition_.rbegin()->second.endPos;
272         }
273         return cachedItemPosition_.rbegin()->second.endPos + spaceWidth_;
274     }
275 
GetTotalItemCount()276     int32_t GetTotalItemCount() const
277     {
278         return totalItemCount_;
279     }
280 
GetFooterIndex()281     int32_t GetFooterIndex() const
282     {
283         return footerIndex_;
284     }
285 
286     float GetChildMaxCrossSize(LayoutWrapper* layoutWrapper, Axis axis);
287 
288     void CheckRecycle(const RefPtr<LayoutWrapper>& layoutWrapper, float startPos, float endPos, float referencePos,
289         bool forwardLayout);
290 
SetNeedAllLayout()291     void SetNeedAllLayout()
292     {
293         needAllLayout_ = true;
294     }
295 
296     void CheckNeedAllLayout(const RefPtr<LayoutWrapper>& layoutWrapper, bool forwardLayout);
297 
SetScrollAlign(ScrollAlign align)298     void SetScrollAlign(ScrollAlign align)
299     {
300         scrollAlign_ = align;
301     }
302 
303     std::pair<float, float> GetItemGroupPosition(int32_t index);
304 
GetHeaderMainSize()305     float GetHeaderMainSize() const
306     {
307         return headerMainSize_;
308     }
309 
GetFooterMainSize()310     float GetFooterMainSize() const
311     {
312         return footerMainSize_;
313     }
314 
315     float GetItemHeight(int32_t index);
316 
GetItemStartIndex()317     int32_t GetItemStartIndex()
318     {
319         return itemStartIndex_;
320     }
321 
SetLayoutedItemInfo(const std::optional<LayoutedItemInfo> & itemInfo)322     void SetLayoutedItemInfo(const std::optional<LayoutedItemInfo>& itemInfo)
323     {
324         layoutedItemInfo_ = itemInfo;
325     }
326 
GetLayoutedItemInfo()327     std::optional<LayoutedItemInfo> GetLayoutedItemInfo() const
328     {
329         return layoutedItemInfo_;
330     }
331 
SetListChildrenMainSize(const RefPtr<ListChildrenMainSize> & childrenMainSize)332     void SetListChildrenMainSize(const RefPtr<ListChildrenMainSize>& childrenMainSize)
333     {
334         childrenSize_ = childrenMainSize;
335     }
336 
SetListPositionMap(const RefPtr<ListPositionMap> & posMap)337     void SetListPositionMap(const RefPtr<ListPositionMap>& posMap)
338     {
339         posMap_ = posMap;
340     }
341 
342     void AdjustByPosMap();
343 
344     static void SyncGeometry(RefPtr<LayoutWrapper>& wrapper);
345 
GetStartHeaderPos()346     float GetStartHeaderPos() const
347     {
348         return startHeaderPos_;
349     }
350 
GetEndFooterPos()351     float GetEndFooterPos() const
352     {
353         return endFooterPos_;
354     }
355 
SetCacheParam(std::optional<ListItemGroupCacheParam> param)356     void SetCacheParam(std::optional<ListItemGroupCacheParam> param)
357     {
358         cacheParam_ = param;
359     }
360 
GetCacheParam()361     std::optional<ListItemGroupCacheParam> GetCacheParam() const
362     {
363         return cacheParam_;
364     }
365 
SetNeedMeasureFormLastItem(bool needMeasureFormLastItem)366     void SetNeedMeasureFormLastItem(bool needMeasureFormLastItem)
367     {
368         isNeedMeasureFormLastItem_ = needMeasureFormLastItem;
369     }
370 
SetNeedSyncLoad(bool value)371     void SetNeedSyncLoad(bool value)
372     {
373         isNeedSyncLoad_ = value;
374     }
375 
SetPrevMeasureBreak(bool value)376     void SetPrevMeasureBreak(bool value)
377     {
378         prevMeasureBreak_ = value;
379     }
380 
GroupMeasureInNextFrame()381     bool GroupMeasureInNextFrame() const
382     {
383         return measureInNextFrame_;
384     }
385 
ReachResponseDeadline(LayoutWrapper * layoutWrapper)386     bool ReachResponseDeadline(LayoutWrapper* layoutWrapper) const
387     {
388         return !itemPosition_.empty() && !isNeedSyncLoad_ && layoutWrapper->ReachResponseDeadline();
389     }
390 
391     ListItemGroupLayoutInfo GetLayoutInfo() const;
392 
GetAdjustReferenceDelta()393     float GetAdjustReferenceDelta() const
394     {
395         return adjustReferenceDelta_;
396     }
397 
GetAdjustTotalSize()398     float GetAdjustTotalSize() const
399     {
400         return adjustTotalSize_;
401     }
402 
SetCachedIndex(int32_t forwardIndex,int32_t backwardIndex)403     void SetCachedIndex(int32_t forwardIndex, int32_t backwardIndex)
404     {
405         forwardCachedIndex_ = forwardIndex;
406         backwardCachedIndex_ = backwardIndex;
407     }
408 
GetCachedIndex()409     std::pair<int32_t, int32_t> GetCachedIndex() const
410     {
411         return { forwardCachedIndex_, backwardCachedIndex_ };
412     }
413 
GetListItemCount()414     int32_t GetListItemCount() const
415     {
416         return static_cast<int32_t>(itemPosition_.size());
417     }
418 
SetPrevTotalItemCount(int32_t prevTotalItemCount)419     void SetPrevTotalItemCount(int32_t prevTotalItemCount)
420     {
421         prevTotalItemCount_ = prevTotalItemCount;
422     }
423 
SetPrevTotalMainSize(float prevTotalMainSize)424     void SetPrevTotalMainSize(float prevTotalMainSize)
425     {
426         prevTotalMainSize_ = prevTotalMainSize;
427     }
428 
GetStackFromEnd()429     bool GetStackFromEnd() const
430     {
431         return isStackFromEnd_;
432     }
433 
434     void ReverseItemPosition(ListItemGroupLayoutAlgorithm::PositionMap &itemPosition, int32_t totalItemCount,
435         float mainSize);
436 
437     void ReverseLayoutedItemInfo(int32_t totalItemCount, float mainSize);
438 
439     void ResetLayoutItem(LayoutWrapper* layoutWrapper);
440 
441 private:
442     float CalculateLaneCrossOffset(float crossSize, float childCrossSize);
443     void UpdateRecycledItems();
444     void UpdateListItemConstraint(const OptionalSizeF& selfIdealSize, LayoutConstraintF& contentConstraint);
445     void LayoutListItem(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize);
446     void LayoutListItemAll(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, float startPos);
447     void LayoutHeaderFooterRTL(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize);
448     void LayoutHeaderFooterLTR(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize);
449     void UpdateZIndex(const RefPtr<LayoutWrapper>& layoutWrapper);
450     void LayoutIndex(const RefPtr<LayoutWrapper>& wrapper, const OffsetF& paddingOffset,
451         float crossSize, float startPos);
452     RefPtr<LayoutWrapper> GetListItem(LayoutWrapper *layoutWrapper, int32_t index, bool addToRenderTree = true,
453                                       bool isCache = false) const
454     {
455         index = !isStackFromEnd_ ? index : totalItemCount_ - index - 1;
456         if (index < 0) {
457             return nullptr;
458         }
459         return layoutWrapper->GetOrCreateChildByIndex(index + itemStartIndex_, addToRenderTree, isCache);
460     }
461     void CalculateLanes(const RefPtr<ListLayoutProperty>& layoutProperty,
462         const LayoutConstraintF& layoutConstraint, std::optional<float> crossSizeOptional, Axis axis);
463 
464     void MeasureListItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint);
465     int32_t MeasureALineForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
466         int32_t& currentIndex, float startPos, float& endPos);
467     int32_t MeasureALineBackward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
468         int32_t& currentIndex, float endPos, float& startPos);
469     int32_t MeasureALineCenter(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
470         int32_t currentIndex);
471     int32_t MeasureALineAuto(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
472         int32_t currentIndex);
473     bool CheckJumpForwardForBigOffset(int32_t& startIndex, float& startPos);
474     bool CheckJumpBackwardForBigOffset(int32_t& endIndex, float& endPos);
475     void MeasureForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
476         int32_t startIndex, float startPos);
477     void MeasureBackward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
478         int32_t endIndex, float endPos);
479     void MeasureJumpToItemForward(LayoutWrapper* layoutWrapper,
480         const LayoutConstraintF& layoutConstraint, int32_t startIndex, float startPos);
481     void MeasureJumpToItemBackward(LayoutWrapper* layoutWrapper,
482         const LayoutConstraintF& layoutConstraint, int32_t endIndex, float endPos);
483     void MeasureCenter(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex);
484     void MeasureStart(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex);
485     void MeasureEnd(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex);
486     void MeasureAuto(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex);
487     void MeasureHeaderFooter(LayoutWrapper* layoutWrapper);
488     void SetActiveChildRange(LayoutWrapper* layoutWrapper, int32_t cacheCount, bool show);
489     float UpdateReferencePos(RefPtr<LayoutProperty> layoutProperty, bool forwardLayout, float referencePos);
490     bool NeedMeasureItem(LayoutWrapper* layoutWrapper);
491     static void SetListItemIndex(const LayoutWrapper* groupLayoutWrapper,
492         const RefPtr<LayoutWrapper>& itemLayoutWrapper, int32_t indexInGroup);
493     bool IsCardStyleForListItemGroup(const LayoutWrapper* groupLayoutWrapper);
494     void UpdateListItemGroupMaxWidth(const OptionalSizeF& parentIdealSize, RefPtr<LayoutProperty> layoutProperty,
495         OptionalSizeF& contentIdealSize);
496     void AdjustItemPosition();
497     bool CheckNeedMeasure(const RefPtr<LayoutWrapper>& layoutWrapper) const;
498     void MeasureCacheItem(LayoutWrapper* layoutWrapper);
499     void MeasureCacheForward(LayoutWrapper* layoutWrapper, ListItemGroupCacheParam& param);
500     void MeasureCacheBackward(LayoutWrapper* layoutWrapper, ListItemGroupCacheParam& param);
501     void LayoutCacheItem(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize, bool show);
502     void CheckUpdateGroupAndItemPos(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize);
503     void UpdateCachedItemPosition(int32_t cacheCount);
504     void UpdateLayoutedItemInfo();
505     void ReportGetChildError(const std::string& funcName, int32_t index) const;
506     bool IsRoundingMode(LayoutWrapper* layoutWrapper);
507 
508     bool isCardStyle_ = false;
509     int32_t headerIndex_;
510     int32_t footerIndex_;
511     int32_t itemStartIndex_;
512     int32_t footerCount_;
513     RefPtr<ListLayoutProperty> listLayoutProperty_;
514     float paddingBeforeContent_ = 0.0f;
515     float paddingAfterContent_ = 0.0f;
516 
517     PositionMap itemPosition_;
518     RefPtr<ListChildrenMainSize> childrenSize_;
519     RefPtr<ListPositionMap> posMap_;
520     Axis axis_ = Axis::VERTICAL;
521     int32_t lanes_ = 1;
522     float laneGutter_ = 0.0f;
523     std::optional<float> minLaneLength_;
524     std::optional<float> maxLaneLength_;
525     V2::ListItemAlign itemAlign_ = V2::ListItemAlign::START;
526     float spaceWidth_ = 0.0f;
527 
528     std::optional<int32_t> jumpIndex_;
529     std::optional<int32_t> targetIndex_;
530     ScrollAlign scrollAlign_ = ScrollAlign::NONE;
531     int32_t totalItemCount_ = 0;
532     int32_t prevTotalItemCount_ = 0;
533     int32_t forwardCachedIndex_ = -1;
534     int32_t backwardCachedIndex_ = INT_MAX;
535     float totalMainSize_ = 0.0f;
536     float prevTotalMainSize_ = 0.0f;
537     float headerMainSize_ = 0.0f;
538     float footerMainSize_ = 0.0f;
539     float startPos_ = 0.0f;
540     float startHeaderPos_ = 0.0f;
541     float endFooterPos_ = 0.0f;
542     float prevStartPos_ = 0.0f;
543     float prevEndPos_ = 0.0f;
544     float endPos_ = 0.0f;
545     float referencePos_ = 0.0f;
546     float adjustReferenceDelta_ = 0.0f;
547     float adjustTotalSize_ = 0.0f;
548     float refPos_ = 0.0f;
549     float prevContentMainSize_ = 0.0f;
550     float contentStartOffset_ = 0.0f;
551     float contentEndOffset_ = 0.0f;
552     float groupItemAverageHeight_ = 0.0f;
553     bool forwardLayout_ = true;
554     bool needAllLayout_ = false;
555     bool needAdjustRefPos_ = false;
556     bool isNeedCheckOffset_ = false;
557     bool isNeedMeasureFormLastItem_ = false;
558     bool isNeedSyncLoad_ = false;
559     bool measureInNextFrame_ = false;
560     bool prevMeasureBreak_ = false;
561     int32_t pauseMeasureCacheItem_ = -1;
562 
563     std::optional<LayoutedItemInfo> layoutedItemInfo_;
564     LayoutConstraintF childLayoutConstraint_;
565     TextDirection layoutDirection_ = TextDirection::LTR;
566 
567     std::optional<ListItemGroupCacheParam> cacheParam_;
568     PositionMap cachedItemPosition_;
569     PositionMap recycledItemPosition_;
570 
571     bool isStackFromEnd_ = false;
572     bool isLayouted_ = true;
573 };
574 } // namespace OHOS::Ace::NG
575 
576 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_LAYOUT_ALGORITHM_H
577