Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- interface ITasksPageDescriptor {
- size: number;
- start: number;
- };
- class Task {
- id: number;
- subTasksCount: number;
- constructor(id, subTasksCount = 0) {
- this.id = id;
- this.subTasksCount = subTasksCount;
- }
- }
- type TTaskRecord = {
- task: Task | null;
- index: number;
- };
- /**
- * Метод для циклического линейного поиска в массиве.
- * @param arr - массив.
- * @param from - индекс, начиная начиная с которого в левую сторону должен будет начаться поиск.
- * @param predicate - предикат поиска.
- * @returns индекс искомого эл-та или null.
- */
- function indexOfInCircle<T>(arr: T[], from: number, predicate: (el: T) => boolean) {
- // Здесь оступаем на 1 вправо, чтобы пройтись начиная с некоторой окрестности вокруг from.
- let itI = Math.min(from + 1, arr.length - 1);
- while (itI >= 0) {
- if (predicate(arr[itI])) {
- return itI;
- }
- --itI;
- }
- itI = arr.length - 1;
- while (itI > from) {
- if (predicate(arr[itI])) {
- return itI;
- }
- --itI;
- }
- return -1;
- }
- class TasksCache {
- private readonly size: number;
- private readonly store: TTaskRecord[];
- private storePtr: number = 0;
- private hidden: HiddenTasks;
- /**
- * Максимальный возможный размер сохраняемой страницы работ.
- */
- private maxPageSize: number;
- constructor(hidden: HiddenTasks, size = 100, maxPageSize = 20) {
- this.size = size;
- this.store = Array(size);
- this.maxPageSize = maxPageSize;
- this.hidden = hidden;
- for (let i = 0; i < size; ++i) {
- this.store[i] = {
- task: null,
- index: -Infinity
- };
- }
- }
- /**
- * Метод, сохраняющий одну страницу работ.
- * @param tasks - массив работ.
- * @param jobIndexes - массив порядковых номеров работ в массиве tasks порядку.
- */
- insertTasks(tasks: Task[], jobIndexes: number[]) {
- for (let i = 0; i < jobIndexes.length; ++i) {
- if (tasks[i]) {
- this.store[this.storePtr].index = jobIndexes[i];
- this.store[this.storePtr].task = tasks[i];
- this.storePtr = (this.storePtr + 1) % this.size;
- }
- }
- }
- /**
- * Проверяет наличие работ из указанной страницы.
- * @param pageDescriptor - страница работ.
- */
- checkPage(pageDescriptor: ITasksPageDescriptor) {
- const availableTasksIndexes: number[] = [];
- const needToBeLoaded: number[] = [];
- for (
- let curIndex = pageDescriptor.start;
- availableTasksIndexes.length + needToBeLoaded.length < pageDescriptor.size;
- curIndex += 1
- ) {
- if (this.hidden.check(curIndex)) {
- continue;
- }
- let taskI = this.findTaskI(curIndex);
- if (taskI < 0) {
- needToBeLoaded.push(curIndex);
- continue;
- }
- availableTasksIndexes.push(curIndex);
- // Здесь мы передвигаем storePtr на место, где в последний раз находили нужную работу.
- if (taskI < this.storePtr ? this.storePtr - taskI : taskI - this.storePtr > this.maxPageSize) {
- this.storePtr = taskI;
- }
- }
- return {
- availableTasksIndexes,
- needToBeLoaded
- }
- }
- private findTaskI(index: number) {
- const taskI = indexOfInCircle(this.store, this.storePtr, (it) => it.index === index);
- if (taskI > -1) {
- this.storePtr = taskI;
- }
- return taskI;
- }
- getByIndex(index: number) {
- return this.store[this.findTaskI(index)];
- }
- }
- type THiddenTasks = {
- from: number;
- to: number;
- }
- class HiddenTasks {
- private store: THiddenTasks[];
- private ptr: number;
- constructor() {
- this.store = [];
- this.ptr = 0;
- }
- /**
- * Метод, проверяющий, скрыта ли работа.
- * @param index - индекс проверяемой работы.
- */
- check(index: number) {
- const taskI = indexOfInCircle(this.store, this.ptr, (hiddenSeg) => {
- return hiddenSeg.from <= index && hiddenSeg.to >= index;
- });
- if (taskI >= 0) {
- this.ptr = taskI;
- return true;
- }
- return false;
- }
- /**
- * Метод для добавления отрезка работ.
- * @param fromIndex - начало отрезка.
- * @param count - конец отрезка.
- */
- hide(fromIndex: number, count?: number) {
- this.ptr = indexOfInCircle(this.store, this.ptr, (hiddenTask) => hiddenTask.from > fromIndex);
- if (this.ptr < 0) {
- this.ptr = this.store.length;
- }
- this.store.splice(this.ptr, 0, {
- from: fromIndex,
- to: fromIndex + (count || 1) - 1
- });
- }
- /**
- * Метод для отображения отрезка скрытых работ.
- * @param fromIndex - начало отрезка.
- */
- show(fromIndex: number) {
- const i = indexOfInCircle(this.store, this.ptr, (hiddenTask) => hiddenTask.from === fromIndex);
- if (i < 0) {
- return;
- }
- this.store.splice(i, 1);
- this.ptr = Math.max(i - 1, 0);
- }
- /**
- * Метод для поиска n-ной не скрытой по счету работы.
- * @returns индекс n-ной не скрытой работы.
- */
- findNthVisible(n: number) {
- if (!this.store.length) {
- return n;
- }
- let accumulated = this.store[0].from - 1;
- if (accumulated > n) {
- return n;
- }
- let i = 1;
- while (i < this.store.length && accumulated <= n) {
- accumulated += Math.max(this.store[i].from - this.store[i - 1].to - 1, 0);
- ++i;
- }
- if (accumulated <= n) {
- return this.store[i - 1].to + n - accumulated;
- }
- --i;
- return this.store[i - 1].to + n - (accumulated - (this.store[i].from - this.store[i - 1].to - 1));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement