x86 (IA-32) मशीन कोड, 126 बाइट्स
Hexdump:
60 8b f9 57 33 c0 f2 ae 5e 2b fe 4f 87 fa 8d 1c
12 8b c3 48 f6 e3 c6 04 07 00 48 c6 04 07 20 75
f9 8b ea 4d 53 8d 04 2a 50 53 8b c5 f6 e3 8d 44
68 01 50 53 2b c2 8b c8 50 4b 53 55 53 03 c5 50
f7 d3 53 50 53 95 f6 e2 6b c0 04 50 43 53 51 6a
01 4a 52 6a 01 50 6a ff 51 b0 0a 6a 0b 8b dc 59
8b 6c cb fc 88 04 2f 03 2c cb 89 6c cb fc 83 f9
0a 75 01 ac e2 ea 4a 79 e0 83 c4 58 61 c3
यह थोड़ा लंबा है, इसलिए इसे समझाने के लिए मैं पहले C कोड दूंगा:
void doit(const char* s, char out[])
{
int n = strlen(s);
int w = 2 * n;
int h = w - 1;
int m = n - 1;
memset(out, ' ', h * w);
out[h * w] = 0;
int offset1 = n + m;
int offset2 = w * m + 2 * m + 1; // 2 * n * n - 1
int offset3 = offset2 - n; // 2 * n * n - n - 1
int offset4 = 4 * n * m; // 4 * n * n - 4 * n
int offsets[] = {
offset3, -1,
offset4, 1,
m, 1,
offset3, 1 - w,
offset4, -w,
offset2 - 1, -w,
offset2 - 1, w - 1,
m, w - 1,
offset3, w,
offset2, w,
offset1, w,
};
do
{
char c = *s++;
for (int i = 0; i < 11; ++i)
{
if (i == 9)
c = '\n';
int offset = offsets[i * 2];
assert(offset > 0 && offset < w * h);
out[offset] = c;
offsets[i * 2] += offsets[i * 2 + 1];
}
} while (--n);
}
यहां nइनपुट स्ट्रिंग की लंबाई है।
उत्पादन क्षेत्र के आयाम 2n(चौड़ाई) द्वारा 2n-1(ऊंचाई) हैं। सबसे पहले, यह रिक्त स्थान के साथ सब कुछ भरता है (और एक समाप्ति नल बाइट जोड़ता है)। फिर, यह आउटपुट क्षेत्र में 11 सीधी रेखाओं के साथ यात्रा करता है, और उन्हें पाठ से भरता है:
- 2 लाइनें अंतिम पंक्ति के बाइट्स से भरी हुई हैं (= 10)
- इनपुट स्ट्रिंग के लगातार बाइट्स के साथ 9 लाइनें भरी हुई हैं
प्रत्येक पंक्ति को दो संख्याओं द्वारा दर्शाया जाता है, एक स्टार्ट ऑफ़ और एक स्ट्राइड। मैंने उन दोनों को सरणी में भर दिया offsets, ताकि पहुंच को "आसान" बनाया जा सके।
दिलचस्प हिस्सा सरणी भर रहा है। सरणी में प्रविष्टियों के क्रम के लिए बहुत कम महत्व है; मैंने उन्हें रजिस्टर संघर्षों की संख्या को कम करने के लिए पुनर्व्यवस्थित करने की कोशिश की। इसके अलावा, गणना के तरीके को चुनने में द्विघात सूत्रों को कुछ स्वतंत्रता है; मैंने घटाव की संख्या को कम करने की कोशिश की (क्योंकि जोड़ लचीले द्वारा लागू किए जा सकते हैंLEA निर्देशों निर्देश )।
विधानसभा स्रोत:
pushad;
; // Calculate the length of the input string
mov edi, ecx;
push edi;
xor eax, eax;
repne scasb;
pop esi; // esi = input string
sub edi, esi;
dec edi;
; // Calculate the size of the output area
xchg edi, edx; // edx = n
// edi = output string
lea ebx, [edx + edx]; // ebx = w
mov eax, ebx;
dec eax; // eax = h
mul bl; // eax = w * h
; // Fill the output string with spaces and zero terminate it
mov byte ptr [edi + eax], 0;
myfill:
dec eax;
mov byte ptr [edi + eax], ' ';
jnz myfill;
mov ebp, edx;
dec ebp; // ebp = m
; // Fill the array of offsets
push ebx; // w
lea eax, [edx + ebp];
push eax; // offset1
push ebx; // w
mov eax, ebp;
mul bl;
lea eax, [eax + 2 * ebp + 1];
push eax; // offset2
push ebx; // w
sub eax, edx;
mov ecx, eax; // ecx = offset3
push eax; // offset3
dec ebx;
push ebx; // w - 1
push ebp; // m
push ebx; // w - 1
add eax, ebp;
push eax; // offset2 - 1
not ebx;
push ebx; // -w
push eax; // offset2 - 1
push ebx; // -w
xchg eax, ebp; // eax = m
mul dl;
imul eax, eax, 4;
push eax; // offset4
inc ebx;
push ebx; // 1 - w
push ecx; // offset3
push 1;
dec edx; // edx = n - 1
push edx;
push 1;
push eax;
push -1;
push ecx;
; // Use the array of offsets to write stuff to output
myout:
mov al, '\n';
push 11;
mov ebx, esp;
pop ecx;
myloop:
mov ebp, [ebx + ecx * 8 - 4];
mov [edi + ebp], al;
add ebp, [ebx + ecx * 8];
mov [ebx + ecx * 8 - 4], ebp;
cmp ecx, 10;
jne skip_read;
lodsb;
skip_read:
loop myloop;
dec edx;
jns myout;
add esp, 11 * 8;
popad;
ret;
मैंने यहां बाइट गुणा का उपयोग किया है, इनपुट स्ट्रिंग की लंबाई 127 तक सीमित कर दी है। यह रजिस्टर को क्लॉबरिंग करने से बचता है edx- उत्पाद की गणनाax इसके बजाय ।
एक छोटी सी गड़बड़: सरणी भरते समय, स्ट्रिंग की लंबाई 1 से कम हो जाती है। इसलिए मैंने लूप बाहर निकलने की स्थिति को समायोजित किया:
jns myout
यह -1 तक गिना जाता है।