メモリアロケータ


11

新しい難解なプログラミング言語を設計していて、追加することに決めた機能の1つが動的メモリアロケーターです。あなたの言語は、ユーザーのプログラム空間に特別な専用仮想アドレス空間を指定します。これは、メモリアロケーターが内部状態に使用するアドレス空間とは別のものです。

実装の配布コストを削減するには、コードのサイズをできるだけ小さくする必要があります。

インターフェース

初期化、割り当て、および割り当て解除の3つの機能を提供する必要があります。

初期化

この関数は、単一の正の整数パラメータを取りますN。これは、ユーザーのプログラムのNアドレス空間にN-1バイトがあり、そこからメモリを割り当てるバイトがあることを意味します。アドレス0は「null」用に予約されています。

この関数は、割り当て/割り当て解除の呼び出しの前に1回だけ呼び出されることが保証されています。

この関数は、ユーザープログラムの仮想アドレス空間に物理メモリを割り当てる必要がないことに注意してください。基本的に、空のメモリアロケータの「ルックアンドフィール」を作成しています。

割り当てる

割り当て関数は、割り当てるメモリのバイト数の要求を受け取る必要があります。入力は正であることが保証されています。

関数は、割り当てられたブロックの先頭に整数アドレスを返すか0、要求されたサイズの連続するブロックが利用できないことを示す必要があります。使用可能なサイズの連続したブロックがアドレス空間のどこでも使用できる場合、割り当てる必要があります

割り当てられた2つのブロックが重複しないようにする必要があります。

割り当て解除

deallocate関数は、割り当てられたブロックの開始アドレスを取得する必要があり、オプションで特定のブロックのサイズを取得することもできます。

割り当て解除されたメモリは再び割り当てに使用できます。入力住所は有効な住所であると想定されます。

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リストが要素ごとに正確に1バイトを占めるとは思えません。「割り当てられたメモリ」はバイト単位である必要がありますか、それとも「あなたの言語の一般的な配列/リスト型」になりますか?
— ドアノブ

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」の文字列を初期化します。

/\B#{?o*n}/は、最初の文字を含まないn個の連続した「o」に一致する正規表現です。 sub!最初の一致をn個の「f」に置き換えます。

"#$`" 一致の左側に文字列、または一致がなかった場合は空の文字列を指定するため、サイズは割り当てられたインデックスまたは0のいずれかになります。

Deallocateは、文字列の指定されたセクションを「o」に戻すだけです。


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

Mathematica、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保存し、内部状態を保存します。アロケータは、割り当てられたメモリの別のセクションのすぐ後ろに割り当てを試みます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.