Advertisement
llyalayk

Gant

Feb 22nd, 2024 (edited)
1,288
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TypeScript 6.14 KB | Source Code | 0 0
  1. interface ITasksPageDescriptor {
  2.   size: number;
  3.   start: number;
  4. };
  5.  
  6. class Task {
  7.   id: number;
  8.   subTasksCount: number;
  9.  
  10.   constructor(id, subTasksCount = 0) {
  11.     this.id = id;
  12.     this.subTasksCount = subTasksCount;
  13.   }
  14. }
  15.  
  16. type TTaskRecord = {
  17.   task: Task | null;
  18.   index: number;
  19. };
  20.  
  21. /**
  22.  * Метод для циклического линейного поиска в массиве.
  23.  * @param arr - массив.
  24.  * @param from - индекс, начиная начиная с которого в левую сторону должен будет начаться поиск.
  25.  * @param predicate - предикат поиска.
  26.  * @returns индекс искомого эл-та или null.
  27.  */
  28. function indexOfInCircle<T>(arr: T[], from: number, predicate: (el: T) => boolean) {
  29.   // Здесь оступаем на 1 вправо, чтобы пройтись начиная с некоторой окрестности вокруг from.
  30.   let itI = Math.min(from + 1, arr.length - 1);
  31.   while (itI >= 0) {
  32.     if (predicate(arr[itI])) {
  33.       return itI;
  34.     }
  35.  
  36.     --itI;
  37.   }
  38.  
  39.   itI = arr.length - 1;
  40.  
  41.   while (itI > from) {
  42.     if (predicate(arr[itI])) {
  43.       return itI;
  44.     }
  45.  
  46.     --itI;
  47.   }
  48.  
  49.   return -1;
  50. }
  51.  
  52. class TasksCache {
  53.   private readonly size: number;
  54.  
  55.   private readonly store: TTaskRecord[];
  56.  
  57.   private storePtr: number = 0;
  58.  
  59.   private hidden: HiddenTasks;
  60.  
  61.   /**
  62.    * Максимальный возможный размер сохраняемой страницы работ.
  63.    */
  64.   private maxPageSize: number;
  65.  
  66.   constructor(hidden: HiddenTasks, size = 100, maxPageSize = 20) {
  67.     this.size = size;
  68.     this.store = Array(size);
  69.     this.maxPageSize = maxPageSize;
  70.     this.hidden = hidden;
  71.  
  72.     for (let i = 0; i < size; ++i) {
  73.       this.store[i] = {
  74.         task: null,
  75.         index: -Infinity
  76.       };
  77.     }
  78.   }
  79.  
  80.   /**
  81.    * Метод, сохраняющий одну страницу работ.
  82.    * @param tasks - массив работ.
  83.    * @param jobIndexes - массив порядковых номеров работ в массиве tasks порядку.
  84.    */
  85.   insertTasks(tasks: Task[], jobIndexes: number[]) {
  86.     for (let i = 0; i < jobIndexes.length; ++i) {
  87.       if (tasks[i]) {
  88.         this.store[this.storePtr].index = jobIndexes[i];
  89.         this.store[this.storePtr].task = tasks[i];
  90.  
  91.         this.storePtr = (this.storePtr + 1) % this.size;
  92.       }
  93.     }
  94.   }
  95.  
  96.   /**
  97.    * Проверяет наличие работ из указанной страницы.
  98.    * @param pageDescriptor - страница работ.
  99.    */
  100.   checkPage(pageDescriptor: ITasksPageDescriptor) {
  101.     const availableTasksIndexes: number[] = [];
  102.     const needToBeLoaded: number[] = [];
  103.  
  104.     for (
  105.       let curIndex = pageDescriptor.start;
  106.       availableTasksIndexes.length + needToBeLoaded.length < pageDescriptor.size;
  107.       curIndex += 1
  108.     ) {
  109.       if (this.hidden.check(curIndex)) {
  110.         continue;
  111.       }
  112.  
  113.       let taskI = this.findTaskI(curIndex);
  114.  
  115.       if (taskI < 0) {
  116.         needToBeLoaded.push(curIndex);
  117.         continue;
  118.       }
  119.  
  120.       availableTasksIndexes.push(curIndex);
  121.  
  122.       // Здесь мы передвигаем storePtr на место, где в последний раз находили нужную работу.
  123.       if (taskI < this.storePtr ? this.storePtr - taskI : taskI - this.storePtr > this.maxPageSize) {
  124.         this.storePtr = taskI;
  125.       }
  126.     }
  127.  
  128.     return {
  129.       availableTasksIndexes,
  130.       needToBeLoaded
  131.     }
  132.   }
  133.  
  134.   private findTaskI(index: number) {
  135.     const taskI = indexOfInCircle(this.store, this.storePtr, (it) => it.index === index);
  136.  
  137.     if (taskI > -1) {
  138.       this.storePtr = taskI;
  139.     }
  140.  
  141.     return taskI;
  142.   }
  143.  
  144.   getByIndex(index: number) {
  145.     return this.store[this.findTaskI(index)];
  146.   }
  147. }
  148.  
  149. type THiddenTasks = {
  150.   from: number;
  151.   to: number;
  152. }
  153.  
  154. class HiddenTasks {
  155.   private store: THiddenTasks[];
  156.  
  157.   private ptr: number;
  158.  
  159.   constructor() {
  160.     this.store = [];
  161.     this.ptr = 0;
  162.   }
  163.  
  164.   /**
  165.    * Метод, проверяющий, скрыта ли работа.
  166.    * @param index - индекс проверяемой работы.
  167.    */
  168.   check(index: number) {
  169.     const taskI = indexOfInCircle(this.store, this.ptr, (hiddenSeg) => {
  170.       return hiddenSeg.from <= index && hiddenSeg.to >= index;
  171.     });
  172.  
  173.     if (taskI >= 0) {
  174.       this.ptr = taskI;
  175.       return true;
  176.     }
  177.  
  178.     return false;
  179.   }
  180.  
  181.   /**
  182.    * Метод для добавления отрезка работ.
  183.    * @param fromIndex - начало отрезка.
  184.    * @param count - конец отрезка.
  185.    */
  186.   hide(fromIndex: number, count?: number) {
  187.     this.ptr = indexOfInCircle(this.store, this.ptr, (hiddenTask) => hiddenTask.from > fromIndex);
  188.     if (this.ptr < 0) {
  189.       this.ptr = this.store.length;
  190.     }
  191.  
  192.     this.store.splice(this.ptr, 0, {
  193.       from: fromIndex,
  194.       to: fromIndex + (count || 1) - 1
  195.     });
  196.   }
  197.  
  198.   /**
  199.    * Метод для отображения отрезка скрытых работ.
  200.    * @param fromIndex - начало отрезка.
  201.    */
  202.   show(fromIndex: number) {
  203.     const i = indexOfInCircle(this.store, this.ptr, (hiddenTask) => hiddenTask.from === fromIndex);
  204.     if (i < 0) {
  205.       return;
  206.     }
  207.  
  208.     this.store.splice(i, 1);
  209.     this.ptr = Math.max(i - 1, 0);
  210.   }
  211.  
  212.   /**
  213.    * Метод для поиска n-ной не скрытой по счету работы.
  214.    * @returns индекс n-ной не скрытой работы.
  215.    */
  216.   findNthVisible(n: number) {
  217.     if (!this.store.length) {
  218.       return n;
  219.     }
  220.  
  221.     let accumulated = this.store[0].from - 1;
  222.  
  223.     if (accumulated > n) {
  224.       return n;
  225.     }
  226.  
  227.     let i = 1;
  228.     while (i < this.store.length && accumulated <= n) {
  229.       accumulated += Math.max(this.store[i].from - this.store[i - 1].to - 1, 0);
  230.       ++i;
  231.     }
  232.  
  233.     if (accumulated <= n) {
  234.       return this.store[i - 1].to + n - accumulated;
  235.     }
  236.  
  237.     --i;
  238.     return this.store[i - 1].to + n - (accumulated - (this.store[i].from - this.store[i - 1].to - 1));
  239.   }
  240. }
  241.  
Tags: react
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement