Розподіл пам'яті


11

Ви розробляєте нову езотеричну мову програмування і однією з особливостей, яку ви вирішили додати, є динамічний розподільник пам'яті. Ваша мова визначає спеціальний віртуальний адресний простір для програмного простору користувача. Це окремо від адресного простору, який використовується розподільником пам'яті для будь-якого внутрішнього стану.

Щоб зменшити витрати на розповсюдження вашої реалізації, розмір коду повинен бути якомога меншим.

Інтерфейс

Ви повинні надати три функції: ініціалізація, розподілення та розміщення.

Ініціалізація

Ця функція приймає єдиний натуральний параметр N. Це означає, що програма користувача має Nв своєму адресному просторі N-1байти, з яких є байти, з яких можна виділити пам'ять. Адреса 0зарезервована для "null".

Гарантується, що ця функція буде викликана рівно один раз перед будь-якими викликами розподілення / угоди.

Зауважте, що цій функції не потрібно виділяти будь-яку фізичну пам'ять для віртуального адресного простору програми користувача; ви в основному створюєте "зовнішній вигляд" порожнього розподільника пам'яті.

Виділити

Функція розподілу повинна приймати запит на кількість байтів пам'яті, яку потрібно виділити. Вхід гарантовано позитивний.

Ваша функція повинна повернути цілу адресу до початку виділеного блоку або 0позначати, що не існує суміжного блоку потрібного розміру. Якщо суміжний блок доступного розміру є в будь-якому місці адресного простору, його потрібно виділити!

Ви повинні переконатися, що два виділені блоки не перетинаються.

Розподіліть

Функція ділокації повинна приймати адресу початку виділеного блоку, і необов'язково може також приймати розмір заданого блоку.

Пам'ять, яка була розміщена, знову доступна для розподілу. Передбачається, що вхідна адреса є дійсною адресою.

Приклад реалізації Python

Зауважте, що ви можете обрати будь-який метод для відстеження внутрішнього стану; в цьому прикладі екземпляр класу відстежує його.

class myallocator:
    def __init__(self, N):
        # address 0 is special, it's always reserved for null
        # address N is technically outside the address space, so use that as a
        # marker
        self.addrs = [0, N]
        self.sizes = [1, 0]

    def allocate(self, size):
        for i,a1,s1,a2 in zip(range(len(self.addrs)),
                                 self.addrs[:-1], self.sizes[:-1],
                                 self.addrs[1:]):
            if(a2 - (a1+s1) >= size):
                # enough available space, take it
                self.addrs.insert(i+1, a1+s1)
                self.sizes.insert(i+1, size)
                return a1+s1
        # no contiguous spaces large enough to take our block
        return 0

    def deallocate(self, addr, size=0):
        # your implementation has the option of taking in a size parameter
        # in this implementation it's not used
        i = self.addrs.index(addr)
        del self.addrs[i]
        del self.sizes[i]

Оцінка балів

Це код гольфу; найкоротший код у байтах виграє. Вам не потрібно турбуватися про втрату пам'яті для будь-якого внутрішнього стану, який вимагає ваш розподільник.

Застосовуються стандартні отвори для петель.

Таблиця лідерів


3
Сумніваюсь, що списки Python займають рівно один байт на елемент. Чи "виділена пам'ять" повинна бути в байтах, чи це просто "загальний масив / тип списку вашої мови"?
Дверна ручка

4
Фактичне виділення не потрібно (за винятком того, що потрібно для внутрішнього відстеження стану, яке знаходиться у власному віртуальному адресному просторі); ви повертаєте цілі числа лише до деякого абстрактного кінцевого віртуального простору адрес.
helloworld922

To help reduce the cost of distributing your implementation the size of the code must be as small as possibleчи це могло бути ефективно (малі та ефективні не однакові)? : D
Кодер


Хоча цей виклик мотивований мовним дизайном, дизайн дизайну мови насправді не є частиною завдання (скоріше реалізацією частин однієї), тому я видалив тег.
Мартін Ендер

Відповіді:


4

Рубі, 80

i,a,d=->n{$m=?o*n},->n{$m.sub!(/\B#{?o*n}/,?f*n);"#$`".size},->n,s{$m[n,s]=?o*s}

Як і відповідь MegaTom, але використовує рядок замість масиву для зберігання стану. Символ "o" позначає відкриту клітинку, а "f" - заповнену. Це дозволяє нам використовувати відносно короткострокові функції маніпулювання рядком Ruby:

?o*n ініціалізує рядок n "o" s.

/\B#{?o*n}/- це регулярний вираз, що відповідає n послідовним символам "o", який не містить першого символу. sub!замінює першу відповідність n "f" s.

"#$`" дає рядок зліва від збігу або порожній рядок, якщо не було відповідності, тому розмір є або виділеним індексом, або 0.

Deallocate просто встановлює позначений ділянку рядка назад на "o" s.


4

JavaScript (ES6), 88

Використання глобальної змінної _( дуже рідкий масив) для відстеження.

Тепер, як я міг це перевірити?

I=n=>(_=[1],_[n]=0)
A=n=>_.some((x,i)=>i-p<n?(p=i+x,0):_[p]=n,p=1)?p:0
D=p=>delete _[p]

3

Рубі, 135

Має глобальний масив відстежувати, виділяється чи ні кожна комірка.

i=->n{$a=[!0]*n;$a[0]=0}
a=->n{s=$a.each_cons(n).to_a.index{|a|a.none?};n.times{|i|$a[s+i]=0}if s;s||0}
d=->s,n{n.times{|i|$a[s+i]=!0}}

1

Математика, 152

i=(n=#;l={{0,1},{#,#}};)&
a=If[#=={},0,l=l~Join~#;#[[1,1]]]&@Cases[l,{Except@n,e_}:>{e,e+#}/;Count[l,{a_,_}/;e<=a<e+#]<1,1,1]&
d=(l=l~DeleteCases~{#,_};)&

nзберігають загальний розмір, lзберігають внутрішній стан. Розподільник спробує виділити прямо за іншим розділом виділеної пам'яті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.