1/* 2 * Copyright (c) 2024 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// eslint-disable-next-line @typescript-eslint/no-unused-vars 17class PrefetchCount { 18 private readonly MAX_SCREENS: number = 4; 19 private readonly speedCoef: number = 2.5; 20 private maxItems = 0; 21 private prefetchCountValueInternal = 0; 22 private currentMaxItemsInternal = 0; 23 private currentMinItemsInternal = 0; 24 25 constructor( 26 private readonly itemsOnScreen: IItemsOnScreenProvider, 27 private readonly prefetchRangeRatio: PrefetchRangeRatio, 28 private readonly logger: ILogger = dummyLogger, 29 ) { 30 this.itemsOnScreen = itemsOnScreen; 31 this.itemsOnScreen.register(() => { 32 this.updateLimits(); 33 }); 34 this.prefetchRangeRatio.register(() => { 35 this.updateLimits(); 36 }); 37 } 38 39 get prefetchCountValue(): number { 40 return this.prefetchCountValueInternal; 41 } 42 43 set prefetchCountValue(v: number) { 44 this.prefetchCountValueInternal = v; 45 this.logger.debug(`{"tm":${Date.now()},"prefetch_count":${v}}`); 46 } 47 48 get currentMaxItems(): number { 49 return this.currentMaxItemsInternal; 50 } 51 52 get currentMinItems(): number { 53 return this.currentMinItemsInternal; 54 } 55 56 getPrefetchCountByRatio(ratio: number): number { 57 this.itemsOnScreen.updateSpeed(this.itemsOnScreen.visibleRange.start, this.itemsOnScreen.visibleRange.end - 1); 58 const minItems = Math.min( 59 this.currentMaxItems, 60 Math.ceil(this.speedCoef * this.itemsOnScreen.speed * this.currentMaxItems), 61 ); 62 const prefetchCount = minItems + Math.ceil(ratio * (this.currentMaxItems - minItems)); 63 this.logger.debug( 64 `speed: ${this.itemsOnScreen.speed}, minItems: ${minItems}, ratio: ${ratio}, prefetchCount: ${prefetchCount}`, 65 ); 66 return prefetchCount; 67 } 68 69 getRangeToFetch(totalCount: number): IndexRange { 70 const visibleRange = this.itemsOnScreen.visibleRange; 71 let start = 0; 72 let end = 0; 73 switch (this.itemsOnScreen.direction) { 74 case 'UNKNOWN': 75 start = Math.max(0, visibleRange.start - Math.round(this.prefetchCountValue)); 76 end = Math.min(totalCount, visibleRange.end + Math.round(this.prefetchCountValue)); 77 break; 78 case 'UP': 79 start = Math.max(0, visibleRange.start - Math.round(this.prefetchCountValue)); 80 end = Math.min(totalCount, visibleRange.end + Math.round(this.prefetchCountValue * 0.5)); 81 break; 82 case 'DOWN': 83 start = Math.max(0, visibleRange.start - Math.round(this.prefetchCountValue * 0.5)); 84 end = Math.min(totalCount, visibleRange.end + Math.round(this.prefetchCountValue)); 85 break; 86 } 87 if (start > end) { 88 start = end; 89 } 90 return new IndexRange(start, end); 91 } 92 93 private updateLimits(): void { 94 this.maxItems = Math.max(this.currentMinItems, Math.ceil(this.MAX_SCREENS * this.itemsOnScreen.meanValue)); 95 this.updateCurrentLimit(); 96 } 97 98 private updateCurrentLimit(): void { 99 this.currentMaxItemsInternal = Math.max( 100 this.currentMinItems, 101 Math.ceil(this.maxItems * this.prefetchRangeRatio.maxRatio), 102 ); 103 this.currentMinItemsInternal = Math.ceil(this.maxItems * this.prefetchRangeRatio.minRatio); 104 } 105} 106