x86マシンコード(32ビット保護モード)、36バイト
52
8B 12
8D 44 91 FC
8B F9
8D 71 04
3B F0
77 10
A7
75 F9
83 EF 04
4A
4A
A5
3B F8
75 FB
97
EB E7
58
89 10
C3
上記のマシンコードのバイトは、配列を入力として受け取り、隣接する重複をインプレースで折りたたみ、結果を返さずに呼び出し元に戻る関数を定義します。これは__fastcall
呼び出し規約に従い、2つのパラメーターをそれぞれECX
とEDX
レジスタに渡します。
最初のパラメーター(ECX
)は、32ビット整数の配列の最初の要素へのポインターです(配列が空の場合、メモリ内の任意の場所を指すことができます)。2番目のパラメーター(EDX
)は、配列の長さを含む32ビット整数へのポインターです。
この関数は、必要に応じて配列の要素をインプレースで変更し、折りたたみ配列の新しい長さを示すために長さも更新します。これは、入力を受け取って出力を返すためのちょっと変わった方法ですが、実際にはアセンブリ言語で他の選択肢はありません。Cと同様に、配列は実際には言語で最初の要素へのポインターとlengthとして表されます。ここで少し奇妙なのは、参照によって長さを取得することですが、そうしなかった場合、配列を短くする方法はありません。コードは正常に機能しますが、折りたたまれた配列の要素の出力をどこで停止するかを呼び出し側が知らないため、出力にはゴミが含まれます。
非ゴルフアセンブリニーモニック:
; void __fastcall CollapseAdjacentDuplicates(int * ptrArray, int * ptrLength);
; ECX = ptrArray ; ECX = fixed ptr to first element
; EDX = ptrLength
push edx ; save pointer to the length
mov edx, [edx] ; EDX = actual length of the array
lea eax, [ecx+edx*4-4] ; EAX = fixed ptr to last element
FindAdjacentPairs:
mov edi, ecx ; EDI = ptr to element A
lea esi, [ecx+4] ; ESI = ptr to element B
FindNext:
cmp esi, eax ; is ptr to element B at end?
ja Finished ; if we've reached the end, we're finished
cmpsd ; compare DWORDs at ESI and EDI, set flags, and increment both by 4
jne FindNext ; keep looping if this is not a pair
; Found an adjacent pair, so remove it from the array.
sub edi, 4 ; undo increment of EDI so it points at element A
dec edx ; decrease length of the array by 2
dec edx ; (two 1-byte DECs are shorter than one 3-byte SUB)
RemoveAdjacentPair:
movsd ; move DWORD at ESI to EDI, and increment both by 4
cmp edi, eax ; have we reached the end?
jne RemoveAdjacentPair ; keep going until we've reached the end
xchg eax, edi ; set new end by updating fixed ptr to last element
jmp FindAdjacentPairs ; restart search for adjacent pairs from beginning
Finished:
pop eax ; retrieve pointer to the length
mov [eax], edx ; update length for caller
ret
実装はC ++ 11の回答に触発されましたが、アセンブリを細かく書き直し、サイズを最適化しました。アセンブリは、はるかに優れたゴルフ言語です。:-)
注:このコードは、文字列命令を使用しているため、あるん方向フラグが(明らかであると仮定DF
== 0)。ABIは通常DFが明確であることを要求するため、これはほとんどのオペレーティング環境で合理的な仮定です。これを保証できない場合は、コードの先頭に1バイトのCLD
命令(0xFC
)を挿入する必要があります。
また、前述のように、32ビット保護モード、具体的には、余分なセグメント(ES
)がデータセグメント(DS
)と同じ「フラット」メモリモデルを想定しています。