OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / term / z-util.cpp
1 /* File: z-util.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11 /* Purpose: Low level utilities -BEN- */
12
13 #include "term/z-util.h"
14
15 /*
16  * Convenient storage of the program name
17  */
18 concptr argv0 = nullptr;
19
20 /*
21  * Determine if string "t" is equal to string "t"
22  */
23 bool streq(std::string_view a, std::string_view b)
24 {
25     return a == b;
26 }
27
28 /*
29  * Determine if string "t" is a suffix of string "s"
30  */
31 bool suffix(std::string_view s, std::string_view t)
32 {
33     //! @todo C++20 では ends_with が使用可能
34     if (t.size() > s.size()) {
35         return false;
36     }
37
38     return s.compare(s.size() - t.size(), s.npos, t) == 0;
39 }
40
41 /*
42  * Determine if string "t" is a prefix of string "s"
43  */
44 bool prefix(std::string_view s, std::string_view t)
45 {
46     //! @todo C++20 では starts_with が使用可能
47     return s.substr(0, t.size()) == t;
48 }
49
50 /*
51  * Redefinable "plog" action
52  */
53 void (*plog_aux)(concptr) = nullptr;
54
55 /*
56  * Print (or log) a "warning" message (ala "perror()")
57  * Note the use of the (optional) "plog_aux" hook.
58  */
59 void plog(concptr str)
60 {
61     /* Use the "alternative" function if possible */
62     if (plog_aux) {
63         (*plog_aux)(str);
64     }
65
66     /* Just do a labeled fprintf to stderr */
67     else {
68         (void)(fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "???", str));
69     }
70 }
71
72 /*
73  * Redefinable "quit" action
74  */
75 void (*quit_aux)(concptr) = nullptr;
76
77 /*
78  * Exit (ala "exit()").  If 'str' is nullptr, do "exit(0)".
79  * If 'str' begins with "+" or "-", do "exit(atoi(str))".
80  * Otherwise, plog() 'str' and exit with an error code of -1.
81  * But always use 'quit_aux', if set, before anything else.
82  */
83 void quit(concptr str)
84 {
85     /* Attempt to use the aux function */
86     if (quit_aux) {
87         (*quit_aux)(str);
88     }
89
90     /* Success */
91     if (!str) {
92         (void)(exit(0));
93     }
94
95     /* Extract a "special error code" */
96     if ((str[0] == '-') || (str[0] == '+')) {
97         (void)(exit(atoi(str)));
98     }
99
100     /* Send the string to plog() */
101     plog(str);
102
103     /* Failure */
104     (void)(exit(EXIT_FAILURE));
105 }
106
107 /*
108  * Redefinable "core" action
109  */
110 void (*core_aux)(concptr) = nullptr;
111
112 /*
113  * @brief 意図的にクラッシュさせ、コアファイルをダンプする
114  * @param str エラーメッセージ
115  * @details MSVC以外のコンパイラはpragma warning をコンパイルエラーにする.
116  * 汚いがプリプロで分岐する.
117  */
118 void core(concptr str)
119 {
120     char *crash = nullptr;
121     if (core_aux) {
122         (*core_aux)(str);
123     }
124
125     if (str) {
126         plog(str);
127     }
128
129 #if defined(_MSC_VER)
130 #pragma warning(push)
131 #pragma warning(disable : 6011)
132 #endif
133     *crash = *crash;
134 #if defined(_MSC_VER)
135 #pragma warning(pop)
136 #endif
137     quit("core() failed");
138 }
139
140 /*** 64-bit integer operations ***/
141
142 void s64b_lshift(int32_t *hi, uint32_t *lo, const int n)
143 {
144     if (n == 0) {
145         return;
146     }
147
148     *hi = (int32_t)((uint32_t)(*hi << n) | (*lo >> (32 - n)));
149     *lo <<= n;
150 }
151
152 void s64b_rshift(int32_t *hi, uint32_t *lo, const int n)
153 {
154     if (n == 0) {
155         return;
156     }
157
158     *lo = ((uint32_t)*hi << (32 - n)) | (*lo >> n);
159     *hi >>= n;
160 }
161
162 /* Add B to A */
163 void s64b_add(int32_t *A1, uint32_t *A2, int32_t B1, uint32_t B2)
164 {
165     (*A2) += B2;
166
167     /* Overflawed? */
168     if ((*A2) < B2) {
169         (*A1) += B1 + 1;
170     } else {
171         (*A1) += B1;
172     }
173 }
174
175 /* Subtract B from A */
176 void s64b_sub(int32_t *A1, uint32_t *A2, int32_t B1, uint32_t B2)
177 {
178     /* Underflaw? */
179     if ((*A2) < B2) {
180         (*A1) -= B1 + 1;
181     } else {
182         (*A1) -= B1;
183     }
184
185     (*A2) -= B2;
186 }
187
188 /*
189  * Multiply A by B
190  *
191  * (A1*2^32 + A2h*2^16 + A2l) * (B1*2^32 + B2h*2^16 + B2l)
192  *  = (A1*B2 & 0xffffffff)*2^32
193  *   +(A2*B1 & 0xffffffff)*2^32
194  *   +(A2h*B2h & 0xffffffff)*2^32
195  *   +(A2h*B2l & 0xffff0000)*2^16
196  *   +(A2l*B2h & 0xffff0000)*2^16
197  *   +(A2*B2 & 0xffffffff)
198  */
199 void s64b_mul(int32_t *A1, uint32_t *A2, int32_t B1, uint32_t B2)
200 {
201     int32_t tmp1;
202     uint32_t A2val = (*A2);
203
204     uint32_t B2high = (B2 >> 16);
205     uint32_t A2high = (A2val >> 16);
206
207     (*A2) *= B2;
208     tmp1 = (*A1) * B2;
209     tmp1 += A2val * B1;
210     tmp1 += A2high * B2high;
211     tmp1 += (A2high * (uint16_t)B2) >> 16;
212     tmp1 += ((uint16_t)A2val * B2high) >> 16;
213
214     (*A1) = tmp1;
215 }
216
217 /* Compare A to B */
218 int s64b_cmp(int32_t A1, uint32_t A2, int32_t B1, uint32_t B2)
219 {
220     if (A1 > B1) {
221         return 1;
222     }
223     if (A1 < B1) {
224         return -1;
225     }
226     if (A2 > B2) {
227         return 1;
228     }
229     if (A2 < B2) {
230         return -1;
231     }
232     return 0;
233 }
234
235 /*
236  * Divide A by B
237  *
238  * Assumes that both A and B are positive
239  */
240 void s64b_div(int32_t *A1, uint32_t *A2, int32_t B1, uint32_t B2)
241 {
242     int32_t result1 = 0;
243     uint32_t result2 = 0;
244     int32_t A1val = (*A1);
245     uint32_t A2val = (*A2);
246     int bit = 0;
247
248     /* No result for B==0 */
249     if (B1 == 0 && B2 == 0) {
250         return;
251     }
252
253     /*
254      * Find the highest bit of quotient
255      */
256     while (s64b_cmp(A1val, A2val, B1, B2) == 1) {
257         s64b_lshift(&B1, &B2, 1);
258         bit++;
259     }
260
261     /* Extract bits of quotient one by one */
262     while (bit >= 0) {
263         if (s64b_cmp(A1val, A2val, B1, B2) >= 0) {
264             if (bit >= 32) {
265                 result1 |= (0x00000001UL << (bit - 32));
266             } else {
267                 result2 |= (0x00000001UL << bit);
268             }
269
270             s64b_sub(&A1val, &A2val, B1, B2);
271         }
272
273         s64b_rshift(&B1, &B2, 1);
274         bit--;
275     }
276
277     (*A1) = result1;
278     (*A2) = result2;
279 }
280
281 /* Reminder of ENERGY_DIVISION (A % B) */
282 void s64b_mod(int32_t *A1, uint32_t *A2, int32_t B1, uint32_t B2)
283 {
284     int32_t tmp1 = (*A1);
285     uint32_t tmp2 = (*A2);
286
287     s64b_div(&tmp1, &tmp2, B1, B2);
288     s64b_mul(&tmp1, &tmp2, B1, B2);
289     s64b_sub(A1, A2, tmp1, tmp2);
290 }
291
292 /*!
293  * @brief 符号なし32ビット整数のビット数を返す。
294  * @param x ビット数を調べたい変数
295  * @return ビット数
296  */
297 int count_bits(BIT_FLAGS x)
298 {
299     int n = 0;
300
301     if (x) {
302         do {
303             n++;
304         } while (0 != (x = x & (x - 1)));
305     }
306
307     return n;
308 }