Последствия реинициализация массива с изменением длинны.

Программирование на Юнити.

Re: Последствия реинициализация массива с изменением длинны.

Сообщение jetyb 08 май 2019, 12:49

Со скуки перед праздниками написал блочный список.
Хранит данные в массиве массивов. В случае добавления данных изменяться может только общий массив. Но его можно изначально сделать большим -(вместимость списка = размер массива x 2 ^ BlockSize).
Проверками границ особо не заботился.
На хрена такой класс нужен - слабо представляю.
Синтаксис:
Используется csharp
        public class JaggedList<T>
        {
            private const int BlockSize = 10; // сделать 2 для теста
            private const int BlockOffset= 1 << BlockSize;
            private const int BlockMask = BlockOffset - 1;
            private T[][] _intances;
            public int count;
            public int capacity;
            public T this[int index]
            {
                get
                {
                    if(index < 0 || index >= capacity) throw new IndexOutOfRangeException();
                    return _intances[index >> BlockSize][index & BlockMask];
                }
                set
                {
                    if (index < 0 || index >= capacity) throw new IndexOutOfRangeException();
                    _intances[index >> BlockSize][index & BlockMask] = value;
                }
            }

            public JaggedList(int cap = 4)
            {                
                _intances = new T[(cap >> BlockSize) + 1][];
                Expand(cap);
            }

            public void Expand(int newCapacity)
            {
                var block = capacity >> BlockSize;
                var newBlock = newCapacity >> BlockSize;
                if (newBlock >= _intances.Length) Array.Resize(ref _intances, newBlock + 1);
                for (var i = block; i <= newBlock; i++)
                {
                     if(_intances[i] == null) _intances[i] = new T[BlockOffset];
                }
                capacity = newCapacity;
            }
                                 
            public void Add(T item)
            {
                if(count + 1 >= capacity) Expand(capacity << 1);
                //Expand(capacity + BlockOffset); ?? обычно оптимально по степеням двойки
                this[count] = item;
                count++;
            }

            private void MoveRangeRight(int index, int rangeSize)
            {
                if(count + rangeSize >= capacity) Expand(count + rangeSize);
                for (var i = count - 1; i >= index; i--)
                {
                    var newIndex = i + rangeSize;
                    _intances[newIndex >> BlockSize][newIndex & BlockMask] =
                        _intances[i >> BlockSize][i & BlockMask];
                }
                count += rangeSize;
            }

            public void InsertRange(int index, IList<T> items)
            {
                MoveRangeRight(index, items.Count);
                for (var i = 0; i < items.Count; i++)
                    this[index + i] = items[i];                
            }

            public void Insert(int index, T item)
            {
                MoveRangeRight(index, 1);
                this[index] = item;
            }

            public void RemoveRange(int index, int rangeSize)
            {
                for (var i = index + rangeSize; i < count; i++)
                {
                    var newIndex = i - rangeSize;
                    _intances[newIndex >> BlockSize][newIndex & BlockMask] =
                        _intances[i >> BlockSize][i & BlockMask];
                }

                //Call T Finalizer
                for (var i = count - rangeSize; i < count; i++)
                {
                    _intances[i >> BlockSize][i & BlockMask] = default(T);
                }

                count -= rangeSize;
            }

            public void Clear()
            {
                for (var i = 0; i < count; i++)
                    _intances[i >> BlockSize][i & BlockMask] = default(T);
                count = 0;
            }

            //некрасиво, но предельно прозрачно
            public List<T> ToList()
            {
                var list = new List<T>(capacity);
                for(var i = 0; i < count; i++) list.Add(this[i]);
                return list;
            }
        }
 


Проверка работы:
Синтаксис:
Используется csharp
            var jaggedList = new JaggedList<int>(100);
            for (var i = 0; i < 100; i++)
            {
                jaggedList.Add(i);
            }
            var l1 = jaggedList.ToList();

            jaggedList.InsertRange(2, new int[]{105,106,107});
            var l2 = jaggedList.ToList();

            jaggedList.RemoveRange(5, 3);
            var l3 = jaggedList.ToList();
 
jetyb
Адепт
 
Сообщения: 1408
Зарегистрирован: 31 окт 2011, 17:21

Re: Последствия реинициализация массива с изменением длинны.

Сообщение ~AvA~ 08 май 2019, 15:18

Не знаю зачем нужен такой класс, но наверное кому-то понадобится :)

Я всегда за Capacity, поставил много - будет тебе большой массив сразу и не будет танцев с памятью.. в случае превышения Capacity, List всё равно увеличится.. Зачем изобретать новые классы?
То есть по сути, это тот ответ который был нужен автору темы, если бы он где-то не прочитал в интернетах, что лист плохой и не пошёл изобретать нечто, не разбираясь в том, что плохо почему и прочея.
Не, ну зато весело, тут всё ок )

Покажите на примере, что вот перформанс ухудшился из-за листа, и мы подумаем где именно вы налажали и как это можно зафиксирить )
Аватара пользователя
~AvA~
UNIверсал
 
Сообщения: 356
Зарегистрирован: 17 фев 2015, 13:09

Re: Последствия реинициализация массива с изменением длинны.

Сообщение Cr0c 31 май 2019, 01:38

Хоть и некропост... Я такой "типа массив" себе делал, когда надо было на поле задавать некоторые ячейки в тайлмапе, чтобы индексы могли быть отрицательными и не надо было кучу памяти выделять (использовал для построения дорог через А*)
Синтаксис:
Используется csharp
using System;
using System.Collections.Generic;

[Serializable]
public class ArrayDyn<T> {
    private readonly Dictionary<int, Dictionary<int, T>> array;
    private readonly T                                   defaultValue;

    public T this[int x, int y] {
        get {
            if (!array.ContainsKey(y)) return defaultValue;
            return !array[y].ContainsKey(x) ? defaultValue : array[y][x];
        }
        set {
            if (!array.ContainsKey(y)) array.Add(y, new Dictionary<int, T>());
            if (!array[y].ContainsKey(x)) array[y].Add(x, defaultValue);
            array[y][x] = value;
        }
    }

    public ArrayDyn(T _defaultValue = default(T)) {
        defaultValue = _defaultValue;
        array        = new Dictionary<int, Dictionary<int, T>>();
    }

    public void Clear() {
        foreach (var a in array) {
            a.Value.Clear();
        }
    }
}
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 2972
Зарегистрирован: 19 июн 2015, 13:50
Skype: i_cr0c

Re: Последствия реинициализация массива с изменением длинны.

Сообщение seaman 31 май 2019, 11:58

А зачем Serializable? Он тут совсем ничего не делает. Dictionary не сериализуются, readonly тоже...
seaman
Адепт
 
Сообщения: 8038
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара

Re: Последствия реинициализация массива с изменением длинны.

Сообщение Cr0c 31 май 2019, 18:27

seaman писал(а):А зачем Serializable? Он тут совсем ничего не делает. Dictionary не сериализуются, readonly тоже...

Я там разные варианты пробовал, от них осталось.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 2972
Зарегистрирован: 19 июн 2015, 13:50
Skype: i_cr0c

Пред.

Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6