VirtualBox

source: vbox/trunk/include/iprt/uint128.h

Last change on this file was 101666, checked in by vboxsync, 7 months ago

iprt/uint128.h: Just zero both return values when returning NULL from RTUInt128DivRem. bugref:10541

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.7 KB
Line 
1/** @file
2 * IPRT - RTUINT128U & uint128_t methods.
3 */
4
5/*
6 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef IPRT_INCLUDED_uint128_h
37#define IPRT_INCLUDED_uint128_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <iprt/cdefs.h>
43#include <iprt/types.h>
44#include <iprt/asm.h>
45#include <iprt/asm-math.h>
46
47RT_C_DECLS_BEGIN
48
49/** @defgroup grp_rt_uint128 RTUInt128 - 128-bit Unsigned Integer Methods
50 * @ingroup grp_rt
51 * @{
52 */
53
54
55/**
56 * Test if a 128-bit unsigned integer value is zero.
57 *
58 * @returns true if they are, false if they aren't.
59 * @param pValue The input and output value.
60 */
61DECLINLINE(bool) RTUInt128IsZero(PCRTUINT128U pValue)
62{
63#if ARCH_BITS >= 64
64 return pValue->s.Hi == 0
65 && pValue->s.Lo == 0;
66#else
67 return pValue->DWords.dw0 == 0
68 && pValue->DWords.dw1 == 0
69 && pValue->DWords.dw2 == 0
70 && pValue->DWords.dw3 == 0;
71#endif
72}
73
74
75/**
76 * Set a 128-bit unsigned integer value to zero.
77 *
78 * @returns pResult
79 * @param pResult The result variable.
80 */
81DECLINLINE(PRTUINT128U) RTUInt128SetZero(PRTUINT128U pResult)
82{
83#if ARCH_BITS >= 64
84 pResult->s.Hi = 0;
85 pResult->s.Lo = 0;
86#else
87 pResult->DWords.dw0 = 0;
88 pResult->DWords.dw1 = 0;
89 pResult->DWords.dw2 = 0;
90 pResult->DWords.dw3 = 0;
91#endif
92 return pResult;
93}
94
95
96/**
97 * Set a 128-bit unsigned integer value to the maximum value.
98 *
99 * @returns pResult
100 * @param pResult The result variable.
101 */
102DECLINLINE(PRTUINT128U) RTUInt128SetMax(PRTUINT128U pResult)
103{
104#if ARCH_BITS >= 64
105 pResult->s.Hi = UINT64_MAX;
106 pResult->s.Lo = UINT64_MAX;
107#else
108 pResult->DWords.dw0 = UINT32_MAX;
109 pResult->DWords.dw1 = UINT32_MAX;
110 pResult->DWords.dw2 = UINT32_MAX;
111 pResult->DWords.dw3 = UINT32_MAX;
112#endif
113 return pResult;
114}
115
116
117
118
119/**
120 * Adds two 128-bit unsigned integer values.
121 *
122 * @returns pResult
123 * @param pResult The result variable.
124 * @param pValue1 The first value.
125 * @param pValue2 The second value.
126 */
127DECLINLINE(PRTUINT128U) RTUInt128Add(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
128{
129 pResult->s.Hi = pValue1->s.Hi + pValue2->s.Hi;
130 pResult->s.Lo = pValue1->s.Lo + pValue2->s.Lo;
131 if (pResult->s.Lo < pValue1->s.Lo)
132 pResult->s.Hi++;
133 return pResult;
134}
135
136
137/**
138 * Adds a 128-bit and a 64-bit unsigned integer values.
139 *
140 * @returns pResult
141 * @param pResult The result variable.
142 * @param pValue1 The first value.
143 * @param uValue2 The second value, 64-bit.
144 */
145DECLINLINE(PRTUINT128U) RTUInt128AddU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2)
146{
147 pResult->s.Hi = pValue1->s.Hi;
148 pResult->s.Lo = pValue1->s.Lo + uValue2;
149 if (pResult->s.Lo < pValue1->s.Lo)
150 pResult->s.Hi++;
151 return pResult;
152}
153
154
155/**
156 * Subtracts a 128-bit unsigned integer value from another.
157 *
158 * @returns pResult
159 * @param pResult The result variable.
160 * @param pValue1 The minuend value.
161 * @param pValue2 The subtrahend value.
162 */
163DECLINLINE(PRTUINT128U) RTUInt128Sub(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
164{
165 pResult->s.Lo = pValue1->s.Lo - pValue2->s.Lo;
166 pResult->s.Hi = pValue1->s.Hi - pValue2->s.Hi;
167 if (pResult->s.Lo > pValue1->s.Lo)
168 pResult->s.Hi--;
169 return pResult;
170}
171
172
173/**
174 * Multiplies two 128-bit unsigned integer values.
175 *
176 * @returns pResult
177 * @param pResult The result variable.
178 * @param pValue1 The first value.
179 * @param pValue2 The second value.
180 */
181DECLINLINE(PRTUINT128U) RTUInt128Mul(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
182{
183 RTUINT64U uTmp;
184
185 /* multiply all dwords in v1 by v2.dw0. */
186 pResult->s.Lo = (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw0;
187
188 uTmp.u = (uint64_t)pValue1->DWords.dw1 * pValue2->DWords.dw0;
189 pResult->DWords.dw3 = 0;
190 pResult->DWords.dw2 = uTmp.DWords.dw1;
191 pResult->DWords.dw1 += uTmp.DWords.dw0;
192 if (pResult->DWords.dw1 < uTmp.DWords.dw0)
193 if (pResult->DWords.dw2++ == UINT32_MAX)
194 pResult->DWords.dw3++;
195
196 pResult->s.Hi += (uint64_t)pValue1->DWords.dw2 * pValue2->DWords.dw0;
197 pResult->DWords.dw3 += pValue1->DWords.dw3 * pValue2->DWords.dw0;
198
199 /* multiply dw0, dw1 & dw2 in v1 by v2.dw1. */
200 uTmp.u = (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw1;
201 pResult->DWords.dw1 += uTmp.DWords.dw0;
202 if (pResult->DWords.dw1 < uTmp.DWords.dw0)
203 if (pResult->DWords.dw2++ == UINT32_MAX)
204 pResult->DWords.dw3++;
205
206 pResult->DWords.dw2 += uTmp.DWords.dw1;
207 if (pResult->DWords.dw2 < uTmp.DWords.dw1)
208 pResult->DWords.dw3++;
209
210 pResult->s.Hi += (uint64_t)pValue1->DWords.dw1 * pValue2->DWords.dw1;
211 pResult->DWords.dw3 += pValue1->DWords.dw2 * pValue2->DWords.dw1;
212
213 /* multiply dw0 & dw1 in v1 by v2.dw2. */
214 pResult->s.Hi += (uint64_t)pValue1->DWords.dw0 * pValue2->DWords.dw2;
215 pResult->DWords.dw3 += pValue1->DWords.dw1 * pValue2->DWords.dw2;
216
217 /* multiply dw0 in v1 by v2.dw3. */
218 pResult->DWords.dw3 += pValue1->DWords.dw0 * pValue2->DWords.dw3;
219
220 return pResult;
221}
222
223
224/**
225 * Multiplies an 128-bit unsigned integer by a 64-bit unsigned integer value.
226 *
227 * @returns pResult
228 * @param pResult The result variable.
229 * @param pValue1 The first value.
230 * @param uValue2 The second value, 64-bit.
231 */
232#if defined(RT_ARCH_AMD64)
233RTDECL(PRTUINT128U) RTUInt128MulByU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2);
234#else
235DECLINLINE(PRTUINT128U) RTUInt128MulByU64(PRTUINT128U pResult, PCRTUINT128U pValue1, uint64_t uValue2)
236{
237 uint32_t const uLoValue2 = (uint32_t)uValue2;
238 uint32_t const uHiValue2 = (uint32_t)(uValue2 >> 32);
239 RTUINT64U uTmp;
240
241 /* multiply all dwords in v1 by uLoValue1. */
242 pResult->s.Lo = (uint64_t)pValue1->DWords.dw0 * uLoValue2;
243
244 uTmp.u = (uint64_t)pValue1->DWords.dw1 * uLoValue2;
245 pResult->DWords.dw3 = 0;
246 pResult->DWords.dw2 = uTmp.DWords.dw1;
247 pResult->DWords.dw1 += uTmp.DWords.dw0;
248 if (pResult->DWords.dw1 < uTmp.DWords.dw0)
249 if (pResult->DWords.dw2++ == UINT32_MAX)
250 pResult->DWords.dw3++;
251
252 pResult->s.Hi += (uint64_t)pValue1->DWords.dw2 * uLoValue2;
253 pResult->DWords.dw3 += pValue1->DWords.dw3 * uLoValue2;
254
255 /* multiply dw0, dw1 & dw2 in v1 by uHiValue2. */
256 uTmp.u = (uint64_t)pValue1->DWords.dw0 * uHiValue2;
257 pResult->DWords.dw1 += uTmp.DWords.dw0;
258 if (pResult->DWords.dw1 < uTmp.DWords.dw0)
259 if (pResult->DWords.dw2++ == UINT32_MAX)
260 pResult->DWords.dw3++;
261
262 pResult->DWords.dw2 += uTmp.DWords.dw1;
263 if (pResult->DWords.dw2 < uTmp.DWords.dw1)
264 pResult->DWords.dw3++;
265
266 pResult->s.Hi += (uint64_t)pValue1->DWords.dw1 * uHiValue2;
267 pResult->DWords.dw3 += pValue1->DWords.dw2 * uHiValue2;
268
269 return pResult;
270}
271#endif
272
273
274/**
275 * Multiplies two 64-bit unsigned integer values with 128-bit precision.
276 *
277 * @returns pResult
278 * @param pResult The result variable.
279 * @param uValue1 The first value. 64-bit.
280 * @param uValue2 The second value, 64-bit.
281 */
282DECLINLINE(PRTUINT128U) RTUInt128MulU64ByU64(PRTUINT128U pResult, uint64_t uValue1, uint64_t uValue2)
283{
284#ifdef RT_ARCH_AMD64
285 pResult->s.Lo = ASMMult2xU64Ret2xU64(uValue1, uValue2, &pResult->s.Hi);
286#else
287 uint32_t const uLoValue1 = (uint32_t)uValue1;
288 uint32_t const uHiValue1 = (uint32_t)(uValue1 >> 32);
289 uint32_t const uLoValue2 = (uint32_t)uValue2;
290 uint32_t const uHiValue2 = (uint32_t)(uValue2 >> 32);
291 RTUINT64U uTmp;
292
293 /* Multiply uLoValue1 and uHiValue1 by uLoValue1. */
294 pResult->s.Lo = (uint64_t)uLoValue1 * uLoValue2;
295
296 uTmp.u = (uint64_t)uHiValue1 * uLoValue2;
297 pResult->DWords.dw3 = 0;
298 pResult->DWords.dw2 = uTmp.DWords.dw1;
299 pResult->DWords.dw1 += uTmp.DWords.dw0;
300 if (pResult->DWords.dw1 < uTmp.DWords.dw0)
301 if (pResult->DWords.dw2++ == UINT32_MAX)
302 pResult->DWords.dw3++;
303
304 /* Multiply uLoValue1 and uHiValue1 by uHiValue2. */
305 uTmp.u = (uint64_t)uLoValue1 * uHiValue2;
306 pResult->DWords.dw1 += uTmp.DWords.dw0;
307 if (pResult->DWords.dw1 < uTmp.DWords.dw0)
308 if (pResult->DWords.dw2++ == UINT32_MAX)
309 pResult->DWords.dw3++;
310
311 pResult->DWords.dw2 += uTmp.DWords.dw1;
312 if (pResult->DWords.dw2 < uTmp.DWords.dw1)
313 pResult->DWords.dw3++;
314
315 pResult->s.Hi += (uint64_t)uHiValue1 * uHiValue2;
316#endif
317 return pResult;
318}
319
320
321/**
322 * Multiplies an 128-bit unsigned integer by a 64-bit unsigned integer value,
323 * returning a 256-bit result (top 64 bits are zero).
324 *
325 * @returns pResult
326 * @param pResult The result variable.
327 * @param pValue1 The first value.
328 * @param uValue2 The second value, 64-bit.
329 */
330#if defined(RT_ARCH_AMD64)
331RTDECL(PRTUINT256U) RTUInt128MulByU64Ex(PRTUINT256U pResult, PCRTUINT128U pValue1, uint64_t uValue2);
332#else
333DECLINLINE(PRTUINT256U) RTUInt128MulByU64Ex(PRTUINT256U pResult, PCRTUINT128U pValue1, uint64_t uValue2)
334{
335 /* multiply the two qwords in pValue1 by uValue2. */
336 uint64_t uTmp = 0;
337 pResult->QWords.qw0 = ASMMult2xU64Ret2xU64(pValue1->s.Lo, uValue2, &uTmp);
338 pResult->QWords.qw1 = ASMMult2xU64Ret2xU64(pValue1->s.Hi, uValue2, &pResult->QWords.qw2);
339 pResult->QWords.qw3 = 0;
340 pResult->QWords.qw1 += uTmp;
341 if (pResult->QWords.qw1 < uTmp)
342 pResult->QWords.qw2++; /* This cannot overflow AFAIK: 0xffff*0xffff = 0xFFFE0001 */
343
344 return pResult;
345}
346#endif
347
348
349/**
350 * Multiplies two 128-bit unsigned integer values, returning a 256-bit result.
351 *
352 * @returns pResult
353 * @param pResult The result variable.
354 * @param pValue1 The first value.
355 * @param pValue2 The second value.
356 */
357DECLINLINE(PRTUINT256U) RTUInt128MulEx(PRTUINT256U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
358{
359 RTUInt128MulByU64Ex(pResult, pValue1, pValue2->s.Lo);
360 if (pValue2->s.Hi)
361 {
362 /* Multiply the two qwords in pValue1 by the high part of uValue2. */
363 uint64_t uTmpHi = 0;
364 uint64_t uTmpLo = ASMMult2xU64Ret2xU64(pValue1->s.Lo, pValue2->s.Hi, &uTmpHi);
365 pResult->QWords.qw1 += uTmpLo;
366 if (pResult->QWords.qw1 < uTmpLo)
367 if (++pResult->QWords.qw2 == 0)
368 pResult->QWords.qw3++; /* (cannot overflow, was == 0) */
369 pResult->QWords.qw2 += uTmpHi;
370 if (pResult->QWords.qw2 < uTmpHi)
371 pResult->QWords.qw3++; /* (cannot overflow, was <= 1) */
372
373 uTmpLo = ASMMult2xU64Ret2xU64(pValue1->s.Hi, pValue2->s.Hi, &uTmpHi);
374 pResult->QWords.qw2 += uTmpLo;
375 if (pResult->QWords.qw2 < uTmpLo)
376 pResult->QWords.qw3++; /* (cannot overflow, was <= 2) */
377 pResult->QWords.qw3 += uTmpHi;
378 }
379
380 return pResult;
381}
382
383
384DECLINLINE(PRTUINT128U) RTUInt128DivRem(PRTUINT128U pQuotient, PRTUINT128U pRemainder, PCRTUINT128U pValue1, PCRTUINT128U pValue2);
385
386/**
387 * Divides a 128-bit unsigned integer value by another.
388 *
389 * @returns pResult
390 * @param pResult The result variable.
391 * @param pValue1 The dividend value.
392 * @param pValue2 The divisor value.
393 */
394DECLINLINE(PRTUINT128U) RTUInt128Div(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
395{
396 RTUINT128U Ignored;
397 return RTUInt128DivRem(pResult, &Ignored, pValue1, pValue2);
398}
399
400
401/**
402 * Divides a 128-bit unsigned integer value by another, returning the remainder.
403 *
404 * @returns pResult
405 * @param pResult The result variable (remainder).
406 * @param pValue1 The dividend value.
407 * @param pValue2 The divisor value.
408 */
409DECLINLINE(PRTUINT128U) RTUInt128Mod(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
410{
411 RTUINT128U Ignored;
412 RTUInt128DivRem(&Ignored, pResult, pValue1, pValue2);
413 return pResult;
414}
415
416
417/**
418 * Bitwise AND of two 128-bit unsigned integer values.
419 *
420 * @returns pResult
421 * @param pResult The result variable.
422 * @param pValue1 The first value.
423 * @param pValue2 The second value.
424 */
425DECLINLINE(PRTUINT128U) RTUInt128And(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
426{
427 pResult->s.Hi = pValue1->s.Hi & pValue2->s.Hi;
428 pResult->s.Lo = pValue1->s.Lo & pValue2->s.Lo;
429 return pResult;
430}
431
432
433/**
434 * Bitwise OR of two 128-bit unsigned integer values.
435 *
436 * @returns pResult
437 * @param pResult The result variable.
438 * @param pValue1 The first value.
439 * @param pValue2 The second value.
440 */
441DECLINLINE(PRTUINT128U) RTUInt128Or( PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
442{
443 pResult->s.Hi = pValue1->s.Hi | pValue2->s.Hi;
444 pResult->s.Lo = pValue1->s.Lo | pValue2->s.Lo;
445 return pResult;
446}
447
448
449/**
450 * Bitwise XOR of two 128-bit unsigned integer values.
451 *
452 * @returns pResult
453 * @param pResult The result variable.
454 * @param pValue1 The first value.
455 * @param pValue2 The second value.
456 */
457DECLINLINE(PRTUINT128U) RTUInt128Xor(PRTUINT128U pResult, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
458{
459 pResult->s.Hi = pValue1->s.Hi ^ pValue2->s.Hi;
460 pResult->s.Lo = pValue1->s.Lo ^ pValue2->s.Lo;
461 return pResult;
462}
463
464
465/**
466 * Shifts a 128-bit unsigned integer value @a cBits to the left.
467 *
468 * @returns pResult
469 * @param pResult The result variable.
470 * @param pValue The value to shift.
471 * @param cBits The number of bits to shift it.
472 */
473DECLINLINE(PRTUINT128U) RTUInt128ShiftLeft(PRTUINT128U pResult, PCRTUINT128U pValue, int cBits)
474{
475 cBits &= 127;
476 if (cBits < 64)
477 {
478 pResult->s.Lo = pValue->s.Lo << cBits;
479 pResult->s.Hi = (pValue->s.Hi << cBits) | (pValue->s.Lo >> (64 - cBits));
480 }
481 else
482 {
483 pResult->s.Lo = 0;
484 pResult->s.Hi = pValue->s.Lo << (cBits - 64);
485 }
486 return pResult;
487}
488
489
490/**
491 * Shifts a 128-bit unsigned integer value @a cBits to the right.
492 *
493 * @returns pResult
494 * @param pResult The result variable.
495 * @param pValue The value to shift.
496 * @param cBits The number of bits to shift it.
497 */
498DECLINLINE(PRTUINT128U) RTUInt128ShiftRight(PRTUINT128U pResult, PCRTUINT128U pValue, int cBits)
499{
500 cBits &= 127;
501 if (cBits < 64)
502 {
503 pResult->s.Hi = pValue->s.Hi >> cBits;
504 pResult->s.Lo = (pValue->s.Lo >> cBits) | (pValue->s.Hi << (64 - cBits));
505 }
506 else
507 {
508 pResult->s.Hi = 0;
509 pResult->s.Lo = pValue->s.Hi >> (cBits - 64);
510 }
511 return pResult;
512}
513
514
515/**
516 * Boolean not (result 0 or 1).
517 *
518 * @returns pResult.
519 * @param pResult The result variable.
520 * @param pValue The value.
521 */
522DECLINLINE(PRTUINT128U) RTUInt128BooleanNot(PRTUINT128U pResult, PCRTUINT128U pValue)
523{
524 pResult->s.Lo = pValue->s.Lo || pValue->s.Hi ? 0 : 1;
525 pResult->s.Hi = 0;
526 return pResult;
527}
528
529
530/**
531 * Bitwise not (flips each bit of the 128 bits).
532 *
533 * @returns pResult.
534 * @param pResult The result variable.
535 * @param pValue The value.
536 */
537DECLINLINE(PRTUINT128U) RTUInt128BitwiseNot(PRTUINT128U pResult, PCRTUINT128U pValue)
538{
539 pResult->s.Hi = ~pValue->s.Hi;
540 pResult->s.Lo = ~pValue->s.Lo;
541 return pResult;
542}
543
544
545/**
546 * Assigns one 128-bit unsigned integer value to another.
547 *
548 * @returns pResult
549 * @param pResult The result variable.
550 * @param pValue The value to assign.
551 */
552DECLINLINE(PRTUINT128U) RTUInt128Assign(PRTUINT128U pResult, PCRTUINT128U pValue)
553{
554#if ARCH_BITS >= 64
555 pResult->s.Hi = pValue->s.Hi;
556 pResult->s.Lo = pValue->s.Lo;
557#else
558 pResult->DWords.dw0 = pValue->DWords.dw0;
559 pResult->DWords.dw1 = pValue->DWords.dw1;
560 pResult->DWords.dw2 = pValue->DWords.dw2;
561 pResult->DWords.dw3 = pValue->DWords.dw3;
562#endif
563 return pResult;
564}
565
566
567/**
568 * Assigns a boolean value to 128-bit unsigned integer.
569 *
570 * @returns pValueResult
571 * @param pValueResult The result variable.
572 * @param fValue The boolean value.
573 */
574DECLINLINE(PRTUINT128U) RTUInt128AssignBoolean(PRTUINT128U pValueResult, bool fValue)
575{
576#if ARCH_BITS >= 64
577 pValueResult->s.Lo = fValue;
578 pValueResult->s.Hi = 0;
579#else
580 pValueResult->DWords.dw0 = fValue;
581 pValueResult->DWords.dw1 = 0;
582 pValueResult->DWords.dw2 = 0;
583 pValueResult->DWords.dw3 = 0;
584#endif
585 return pValueResult;
586}
587
588
589/**
590 * Assigns a 8-bit unsigned integer value to 128-bit unsigned integer.
591 *
592 * @returns pValueResult
593 * @param pValueResult The result variable.
594 * @param u8Value The 8-bit unsigned integer value.
595 */
596DECLINLINE(PRTUINT128U) RTUInt128AssignU8(PRTUINT128U pValueResult, uint8_t u8Value)
597{
598#if ARCH_BITS >= 64
599 pValueResult->s.Lo = u8Value;
600 pValueResult->s.Hi = 0;
601#else
602 pValueResult->DWords.dw0 = u8Value;
603 pValueResult->DWords.dw1 = 0;
604 pValueResult->DWords.dw2 = 0;
605 pValueResult->DWords.dw3 = 0;
606#endif
607 return pValueResult;
608}
609
610
611/**
612 * Assigns a 16-bit unsigned integer value to 128-bit unsigned integer.
613 *
614 * @returns pValueResult
615 * @param pValueResult The result variable.
616 * @param u16Value The 16-bit unsigned integer value.
617 */
618DECLINLINE(PRTUINT128U) RTUInt128AssignU16(PRTUINT128U pValueResult, uint16_t u16Value)
619{
620#if ARCH_BITS >= 64
621 pValueResult->s.Lo = u16Value;
622 pValueResult->s.Hi = 0;
623#else
624 pValueResult->DWords.dw0 = u16Value;
625 pValueResult->DWords.dw1 = 0;
626 pValueResult->DWords.dw2 = 0;
627 pValueResult->DWords.dw3 = 0;
628#endif
629 return pValueResult;
630}
631
632
633/**
634 * Assigns a 32-bit unsigned integer value to 128-bit unsigned integer.
635 *
636 * @returns pValueResult
637 * @param pValueResult The result variable.
638 * @param u32Value The 32-bit unsigned integer value.
639 */
640DECLINLINE(PRTUINT128U) RTUInt128AssignU32(PRTUINT128U pValueResult, uint32_t u32Value)
641{
642#if ARCH_BITS >= 64
643 pValueResult->s.Lo = u32Value;
644 pValueResult->s.Hi = 0;
645#else
646 pValueResult->DWords.dw0 = u32Value;
647 pValueResult->DWords.dw1 = 0;
648 pValueResult->DWords.dw2 = 0;
649 pValueResult->DWords.dw3 = 0;
650#endif
651 return pValueResult;
652}
653
654
655/**
656 * Assigns a 64-bit unsigned integer value to 128-bit unsigned integer.
657 *
658 * @returns pValueResult
659 * @param pValueResult The result variable.
660 * @param u64Value The 64-bit unsigned integer value.
661 */
662DECLINLINE(PRTUINT128U) RTUInt128AssignU64(PRTUINT128U pValueResult, uint64_t u64Value)
663{
664 pValueResult->s.Lo = u64Value;
665 pValueResult->s.Hi = 0;
666 return pValueResult;
667}
668
669
670/**
671 * Adds two 128-bit unsigned integer values, storing the result in the first.
672 *
673 * @returns pValue1Result.
674 * @param pValue1Result The first value and result.
675 * @param pValue2 The second value.
676 */
677DECLINLINE(PRTUINT128U) RTUInt128AssignAdd(PRTUINT128U pValue1Result, PCRTUINT128U pValue2)
678{
679 uint64_t const uTmp = pValue1Result->s.Lo;
680 pValue1Result->s.Lo += pValue2->s.Lo;
681 if (pValue1Result->s.Lo < uTmp)
682 pValue1Result->s.Hi++;
683 pValue1Result->s.Hi += pValue2->s.Hi;
684 return pValue1Result;
685}
686
687
688/**
689 * Adds a 64-bit unsigned integer value to a 128-bit unsigned integer values,
690 * storing the result in the 128-bit one.
691 *
692 * @returns pValue1Result.
693 * @param pValue1Result The first value and result.
694 * @param uValue2 The second value, 64-bit.
695 */
696DECLINLINE(PRTUINT128U) RTUInt128AssignAddU64(PRTUINT128U pValue1Result, uint64_t uValue2)
697{
698 pValue1Result->s.Lo += uValue2;
699 if (pValue1Result->s.Lo < uValue2)
700 pValue1Result->s.Hi++;
701 return pValue1Result;
702}
703
704
705/**
706 * Subtracts two 128-bit unsigned integer values, storing the result in the
707 * first.
708 *
709 * @returns pValue1Result.
710 * @param pValue1Result The minuend value and result.
711 * @param pValue2 The subtrahend value.
712 */
713DECLINLINE(PRTUINT128U) RTUInt128AssignSub(PRTUINT128U pValue1Result, PCRTUINT128U pValue2)
714{
715 uint64_t const uTmp = pValue1Result->s.Lo;
716 pValue1Result->s.Lo -= pValue2->s.Lo;
717 if (pValue1Result->s.Lo > uTmp)
718 pValue1Result->s.Hi--;
719 pValue1Result->s.Hi -= pValue2->s.Hi;
720 return pValue1Result;
721}
722
723
724/**
725 * Negates a 128 number, storing the result in the input.
726 *
727 * @returns pValueResult.
728 * @param pValueResult The value to negate.
729 */
730DECLINLINE(PRTUINT128U) RTUInt128AssignNeg(PRTUINT128U pValueResult)
731{
732 /* result = 0 - value */
733 if (pValueResult->s.Lo != 0)
734 {
735 pValueResult->s.Lo = UINT64_C(0) - pValueResult->s.Lo;
736 pValueResult->s.Hi = UINT64_MAX - pValueResult->s.Hi;
737 }
738 else
739 pValueResult->s.Hi = UINT64_C(0) - pValueResult->s.Hi;
740 return pValueResult;
741}
742
743
744/**
745 * Multiplies two 128-bit unsigned integer values, storing the result in the
746 * first.
747 *
748 * @returns pValue1Result.
749 * @param pValue1Result The first value and result.
750 * @param pValue2 The second value.
751 */
752DECLINLINE(PRTUINT128U) RTUInt128AssignMul(PRTUINT128U pValue1Result, PCRTUINT128U pValue2)
753{
754 RTUINT128U Result;
755 RTUInt128Mul(&Result, pValue1Result, pValue2);
756 *pValue1Result = Result;
757 return pValue1Result;
758}
759
760
761/**
762 * Divides a 128-bit unsigned integer value by another, storing the result in
763 * the first.
764 *
765 * @returns pValue1Result.
766 * @param pValue1Result The dividend value and result.
767 * @param pValue2 The divisor value.
768 */
769DECLINLINE(PRTUINT128U) RTUInt128AssignDiv(PRTUINT128U pValue1Result, PCRTUINT128U pValue2)
770{
771 RTUINT128U Result;
772 RTUINT128U Ignored;
773 RTUInt128DivRem(&Result, &Ignored, pValue1Result, pValue2);
774 *pValue1Result = Result;
775 return pValue1Result;
776}
777
778
779/**
780 * Divides a 128-bit unsigned integer value by another, storing the remainder in
781 * the first.
782 *
783 * @returns pValue1Result.
784 * @param pValue1Result The dividend value and result (remainder).
785 * @param pValue2 The divisor value.
786 */
787DECLINLINE(PRTUINT128U) RTUInt128AssignMod(PRTUINT128U pValue1Result, PCRTUINT128U pValue2)
788{
789 RTUINT128U Ignored;
790 RTUINT128U Result;
791 RTUInt128DivRem(&Ignored, &Result, pValue1Result, pValue2);
792 *pValue1Result = Result;
793 return pValue1Result;
794}
795
796
797/**
798 * Performs a bitwise AND of two 128-bit unsigned integer values and assigned
799 * the result to the first one.
800 *
801 * @returns pValue1Result.
802 * @param pValue1Result The first value and result.
803 * @param pValue2 The second value.
804 */
805DECLINLINE(PRTUINT128U) RTUInt128AssignAnd(PRTUINT128U pValue1Result, PCRTUINT128U pValue2)
806{
807#if ARCH_BITS >= 64
808 pValue1Result->s.Hi &= pValue2->s.Hi;
809 pValue1Result->s.Lo &= pValue2->s.Lo;
810#else
811 pValue1Result->DWords.dw0 &= pValue2->DWords.dw0;
812 pValue1Result->DWords.dw1 &= pValue2->DWords.dw1;
813 pValue1Result->DWords.dw2 &= pValue2->DWords.dw2;
814 pValue1Result->DWords.dw3 &= pValue2->DWords.dw3;
815#endif
816 return pValue1Result;
817}
818
819
820/**
821 * Performs a bitwise AND of a 128-bit unsigned integer value and a mask made
822 * up of the first N bits, assigning the result to the the 128-bit value.
823 *
824 * @returns pValueResult.
825 * @param pValueResult The value and result.
826 * @param cBits The number of bits to AND (counting from the first
827 * bit).
828 */
829DECLINLINE(PRTUINT128U) RTUInt128AssignAndNFirstBits(PRTUINT128U pValueResult, unsigned cBits)
830{
831 if (cBits <= 64)
832 {
833 if (cBits != 64)
834 pValueResult->s.Lo &= (RT_BIT_64(cBits) - 1);
835 pValueResult->s.Hi = 0;
836 }
837 else if (cBits < 128)
838 pValueResult->s.Hi &= (RT_BIT_64(cBits - 64) - 1);
839/** @todo \#if ARCH_BITS >= 64 */
840 return pValueResult;
841}
842
843
844/**
845 * Performs a bitwise OR of two 128-bit unsigned integer values and assigned
846 * the result to the first one.
847 *
848 * @returns pValue1Result.
849 * @param pValue1Result The first value and result.
850 * @param pValue2 The second value.
851 */
852DECLINLINE(PRTUINT128U) RTUInt128AssignOr(PRTUINT128U pValue1Result, PCRTUINT128U pValue2)
853{
854#if ARCH_BITS >= 64
855 pValue1Result->s.Hi |= pValue2->s.Hi;
856 pValue1Result->s.Lo |= pValue2->s.Lo;
857#else
858 pValue1Result->DWords.dw0 |= pValue2->DWords.dw0;
859 pValue1Result->DWords.dw1 |= pValue2->DWords.dw1;
860 pValue1Result->DWords.dw2 |= pValue2->DWords.dw2;
861 pValue1Result->DWords.dw3 |= pValue2->DWords.dw3;
862#endif
863 return pValue1Result;
864}
865
866
867/**
868 * ORs in a bit and assign the result to the input value.
869 *
870 * @returns pValue1Result.
871 * @param pValue1Result The first value and result.
872 * @param iBit The bit to set (0 based).
873 */
874DECLINLINE(PRTUINT128U) RTUInt128AssignOrBit(PRTUINT128U pValue1Result, uint32_t iBit)
875{
876#if ARCH_BITS >= 64
877 if (iBit >= 64)
878 pValue1Result->s.Hi |= RT_BIT_64(iBit - 64);
879 else
880 pValue1Result->s.Lo |= RT_BIT_64(iBit);
881#else
882 if (iBit >= 64)
883 {
884 if (iBit >= 96)
885 pValue1Result->DWords.dw3 |= RT_BIT_32(iBit - 96);
886 else
887 pValue1Result->DWords.dw2 |= RT_BIT_32(iBit - 64);
888 }
889 else
890 {
891 if (iBit >= 32)
892 pValue1Result->DWords.dw1 |= RT_BIT_32(iBit - 32);
893 else
894 pValue1Result->DWords.dw0 |= RT_BIT_32(iBit);
895 }
896#endif
897 return pValue1Result;
898}
899
900
901
902/**
903 * Performs a bitwise XOR of two 128-bit unsigned integer values and assigned
904 * the result to the first one.
905 *
906 * @returns pValue1Result.
907 * @param pValue1Result The first value and result.
908 * @param pValue2 The second value.
909 */
910DECLINLINE(PRTUINT128U) RTUInt128AssignXor(PRTUINT128U pValue1Result, PCRTUINT128U pValue2)
911{
912#if ARCH_BITS >= 64
913 pValue1Result->s.Hi ^= pValue2->s.Hi;
914 pValue1Result->s.Lo ^= pValue2->s.Lo;
915#else
916 pValue1Result->DWords.dw0 ^= pValue2->DWords.dw0;
917 pValue1Result->DWords.dw1 ^= pValue2->DWords.dw1;
918 pValue1Result->DWords.dw2 ^= pValue2->DWords.dw2;
919 pValue1Result->DWords.dw3 ^= pValue2->DWords.dw3;
920#endif
921 return pValue1Result;
922}
923
924
925/**
926 * Performs a bitwise left shift on a 128-bit unsigned integer value, assigning
927 * the result to it.
928 *
929 * @returns pValueResult.
930 * @param pValueResult The first value and result.
931 * @param cBits The number of bits to shift.
932 */
933DECLINLINE(PRTUINT128U) RTUInt128AssignShiftLeft(PRTUINT128U pValueResult, int cBits)
934{
935 RTUINT128U const InVal = *pValueResult;
936/** @todo \#if ARCH_BITS >= 64 */
937 if (cBits > 0)
938 {
939 /* (left shift) */
940 if (cBits >= 128)
941 RTUInt128SetZero(pValueResult);
942 else if (cBits >= 64)
943 {
944 pValueResult->s.Lo = 0;
945 pValueResult->s.Hi = InVal.s.Lo << (cBits - 64);
946 }
947 else
948 {
949 pValueResult->s.Hi = InVal.s.Hi << cBits;
950 pValueResult->s.Hi |= InVal.s.Lo >> (64 - cBits);
951 pValueResult->s.Lo = InVal.s.Lo << cBits;
952 }
953 }
954 else if (cBits < 0)
955 {
956 /* (right shift) */
957 cBits = -cBits;
958 if (cBits >= 128)
959 RTUInt128SetZero(pValueResult);
960 else if (cBits >= 64)
961 {
962 pValueResult->s.Hi = 0;
963 pValueResult->s.Lo = InVal.s.Hi >> (cBits - 64);
964 }
965 else
966 {
967 pValueResult->s.Lo = InVal.s.Lo >> cBits;
968 pValueResult->s.Lo |= InVal.s.Hi << (64 - cBits);
969 pValueResult->s.Hi = InVal.s.Hi >> cBits;
970 }
971 }
972 return pValueResult;
973}
974
975
976/**
977 * Performs a bitwise left shift on a 128-bit unsigned integer value, assigning
978 * the result to it.
979 *
980 * @returns pValueResult.
981 * @param pValueResult The first value and result.
982 * @param cBits The number of bits to shift.
983 */
984DECLINLINE(PRTUINT128U) RTUInt128AssignShiftRight(PRTUINT128U pValueResult, int cBits)
985{
986 return RTUInt128AssignShiftLeft(pValueResult, -cBits);
987}
988
989
990/**
991 * Performs a bitwise NOT on a 128-bit unsigned integer value, assigning the
992 * result to it.
993 *
994 * @returns pValueResult
995 * @param pValueResult The value and result.
996 */
997DECLINLINE(PRTUINT128U) RTUInt128AssignBitwiseNot(PRTUINT128U pValueResult)
998{
999#if ARCH_BITS >= 64
1000 pValueResult->s.Hi = ~pValueResult->s.Hi;
1001 pValueResult->s.Lo = ~pValueResult->s.Lo;
1002#else
1003 pValueResult->DWords.dw0 = ~pValueResult->DWords.dw0;
1004 pValueResult->DWords.dw1 = ~pValueResult->DWords.dw1;
1005 pValueResult->DWords.dw2 = ~pValueResult->DWords.dw2;
1006 pValueResult->DWords.dw3 = ~pValueResult->DWords.dw3;
1007#endif
1008 return pValueResult;
1009}
1010
1011
1012/**
1013 * Performs a boolean NOT on a 128-bit unsigned integer value, assigning the
1014 * result to it.
1015 *
1016 * @returns pValueResult
1017 * @param pValueResult The value and result.
1018 */
1019DECLINLINE(PRTUINT128U) RTUInt128AssignBooleanNot(PRTUINT128U pValueResult)
1020{
1021 return RTUInt128AssignBoolean(pValueResult, RTUInt128IsZero(pValueResult));
1022}
1023
1024
1025/**
1026 * Compares two 128-bit unsigned integer values.
1027 *
1028 * @retval 0 if equal.
1029 * @retval -1 if the first value is smaller than the second.
1030 * @retval 1 if the first value is larger than the second.
1031 *
1032 * @param pValue1 The first value.
1033 * @param pValue2 The second value.
1034 */
1035DECLINLINE(int) RTUInt128Compare(PCRTUINT128U pValue1, PCRTUINT128U pValue2)
1036{
1037#if ARCH_BITS >= 64
1038 if (pValue1->s.Hi != pValue2->s.Hi)
1039 return pValue1->s.Hi > pValue2->s.Hi ? 1 : -1;
1040 if (pValue1->s.Lo != pValue2->s.Lo)
1041 return pValue1->s.Lo > pValue2->s.Lo ? 1 : -1;
1042 return 0;
1043#else
1044 if (pValue1->DWords.dw3 != pValue2->DWords.dw3)
1045 return pValue1->DWords.dw3 > pValue2->DWords.dw3 ? 1 : -1;
1046 if (pValue1->DWords.dw2 != pValue2->DWords.dw2)
1047 return pValue1->DWords.dw2 > pValue2->DWords.dw2 ? 1 : -1;
1048 if (pValue1->DWords.dw1 != pValue2->DWords.dw1)
1049 return pValue1->DWords.dw1 > pValue2->DWords.dw1 ? 1 : -1;
1050 if (pValue1->DWords.dw0 != pValue2->DWords.dw0)
1051 return pValue1->DWords.dw0 > pValue2->DWords.dw0 ? 1 : -1;
1052 return 0;
1053#endif
1054}
1055
1056
1057/**
1058 * Tests if a 128-bit unsigned integer value is smaller than another.
1059 *
1060 * @returns true if the first value is smaller, false if not.
1061 * @param pValue1 The first value.
1062 * @param pValue2 The second value.
1063 */
1064DECLINLINE(bool) RTUInt128IsSmaller(PCRTUINT128U pValue1, PCRTUINT128U pValue2)
1065{
1066#if ARCH_BITS >= 64
1067 return pValue1->s.Hi < pValue2->s.Hi
1068 || ( pValue1->s.Hi == pValue2->s.Hi
1069 && pValue1->s.Lo < pValue2->s.Lo);
1070#else
1071 return pValue1->DWords.dw3 < pValue2->DWords.dw3
1072 || ( pValue1->DWords.dw3 == pValue2->DWords.dw3
1073 && ( pValue1->DWords.dw2 < pValue2->DWords.dw2
1074 || ( pValue1->DWords.dw2 == pValue2->DWords.dw2
1075 && ( pValue1->DWords.dw1 < pValue2->DWords.dw1
1076 || ( pValue1->DWords.dw1 == pValue2->DWords.dw1
1077 && pValue1->DWords.dw0 < pValue2->DWords.dw0)))));
1078#endif
1079}
1080
1081
1082/**
1083 * Tests if a 128-bit unsigned integer value is larger than another.
1084 *
1085 * @returns true if the first value is larger, false if not.
1086 * @param pValue1 The first value.
1087 * @param pValue2 The second value.
1088 */
1089DECLINLINE(bool) RTUInt128IsLarger(PCRTUINT128U pValue1, PCRTUINT128U pValue2)
1090{
1091#if ARCH_BITS >= 64
1092 return pValue1->s.Hi > pValue2->s.Hi
1093 || ( pValue1->s.Hi == pValue2->s.Hi
1094 && pValue1->s.Lo > pValue2->s.Lo);
1095#else
1096 return pValue1->DWords.dw3 > pValue2->DWords.dw3
1097 || ( pValue1->DWords.dw3 == pValue2->DWords.dw3
1098 && ( pValue1->DWords.dw2 > pValue2->DWords.dw2
1099 || ( pValue1->DWords.dw2 == pValue2->DWords.dw2
1100 && ( pValue1->DWords.dw1 > pValue2->DWords.dw1
1101 || ( pValue1->DWords.dw1 == pValue2->DWords.dw1
1102 && pValue1->DWords.dw0 > pValue2->DWords.dw0)))));
1103#endif
1104}
1105
1106
1107/**
1108 * Tests if a 128-bit unsigned integer value is larger or equal than another.
1109 *
1110 * @returns true if the first value is larger or equal, false if not.
1111 * @param pValue1 The first value.
1112 * @param pValue2 The second value.
1113 */
1114DECLINLINE(bool) RTUInt128IsLargerOrEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2)
1115{
1116#if ARCH_BITS >= 64
1117 return pValue1->s.Hi > pValue2->s.Hi
1118 || ( pValue1->s.Hi == pValue2->s.Hi
1119 && pValue1->s.Lo >= pValue2->s.Lo);
1120#else
1121 return pValue1->DWords.dw3 > pValue2->DWords.dw3
1122 || ( pValue1->DWords.dw3 == pValue2->DWords.dw3
1123 && ( pValue1->DWords.dw2 > pValue2->DWords.dw2
1124 || ( pValue1->DWords.dw2 == pValue2->DWords.dw2
1125 && ( pValue1->DWords.dw1 > pValue2->DWords.dw1
1126 || ( pValue1->DWords.dw1 == pValue2->DWords.dw1
1127 && pValue1->DWords.dw0 >= pValue2->DWords.dw0)))));
1128#endif
1129}
1130
1131
1132/**
1133 * Tests if two 128-bit unsigned integer values not equal.
1134 *
1135 * @returns true if equal, false if not equal.
1136 * @param pValue1 The first value.
1137 * @param pValue2 The second value.
1138 */
1139DECLINLINE(bool) RTUInt128IsEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2)
1140{
1141#if ARCH_BITS >= 64
1142 return pValue1->s.Hi == pValue2->s.Hi
1143 && pValue1->s.Lo == pValue2->s.Lo;
1144#else
1145 return pValue1->DWords.dw0 == pValue2->DWords.dw0
1146 && pValue1->DWords.dw1 == pValue2->DWords.dw1
1147 && pValue1->DWords.dw2 == pValue2->DWords.dw2
1148 && pValue1->DWords.dw3 == pValue2->DWords.dw3;
1149#endif
1150}
1151
1152
1153/**
1154 * Tests if two 128-bit unsigned integer values are not equal.
1155 *
1156 * @returns true if not equal, false if equal.
1157 * @param pValue1 The first value.
1158 * @param pValue2 The second value.
1159 */
1160DECLINLINE(bool) RTUInt128IsNotEqual(PCRTUINT128U pValue1, PCRTUINT128U pValue2)
1161{
1162 return !RTUInt128IsEqual(pValue1, pValue2);
1163}
1164
1165
1166/**
1167 * Sets a bit in a 128-bit unsigned integer type.
1168 *
1169 * @returns pValueResult.
1170 * @param pValueResult The input and output value.
1171 * @param iBit The bit to set.
1172 */
1173DECLINLINE(PRTUINT128U) RTUInt128BitSet(PRTUINT128U pValueResult, unsigned iBit)
1174{
1175 if (iBit < 64)
1176 {
1177#if ARCH_BITS >= 64
1178 pValueResult->s.Lo |= RT_BIT_64(iBit);
1179#else
1180 if (iBit < 32)
1181 pValueResult->DWords.dw0 |= RT_BIT_32(iBit);
1182 else
1183 pValueResult->DWords.dw1 |= RT_BIT_32(iBit - 32);
1184#endif
1185 }
1186 else if (iBit < 128)
1187 {
1188#if ARCH_BITS >= 64
1189 pValueResult->s.Hi |= RT_BIT_64(iBit - 64);
1190#else
1191 if (iBit < 96)
1192 pValueResult->DWords.dw2 |= RT_BIT_32(iBit - 64);
1193 else
1194 pValueResult->DWords.dw3 |= RT_BIT_32(iBit - 96);
1195#endif
1196 }
1197 return pValueResult;
1198}
1199
1200
1201/**
1202 * Sets a bit in a 128-bit unsigned integer type.
1203 *
1204 * @returns pValueResult.
1205 * @param pValueResult The input and output value.
1206 * @param iBit The bit to set.
1207 */
1208DECLINLINE(PRTUINT128U) RTUInt128BitClear(PRTUINT128U pValueResult, unsigned iBit)
1209{
1210 if (iBit < 64)
1211 {
1212#if ARCH_BITS >= 64
1213 pValueResult->s.Lo &= ~RT_BIT_64(iBit);
1214#else
1215 if (iBit < 32)
1216 pValueResult->DWords.dw0 &= ~RT_BIT_32(iBit);
1217 else
1218 pValueResult->DWords.dw1 &= ~RT_BIT_32(iBit - 32);
1219#endif
1220 }
1221 else if (iBit < 128)
1222 {
1223#if ARCH_BITS >= 64
1224 pValueResult->s.Hi &= ~RT_BIT_64(iBit - 64);
1225#else
1226 if (iBit < 96)
1227 pValueResult->DWords.dw2 &= ~RT_BIT_32(iBit - 64);
1228 else
1229 pValueResult->DWords.dw3 &= ~RT_BIT_32(iBit - 96);
1230#endif
1231 }
1232 return pValueResult;
1233}
1234
1235
1236/**
1237 * Tests if a bit in a 128-bit unsigned integer value is set.
1238 *
1239 * @returns pValueResult.
1240 * @param pValueResult The input and output value.
1241 * @param iBit The bit to test.
1242 */
1243DECLINLINE(bool) RTUInt128BitTest(PRTUINT128U pValueResult, unsigned iBit)
1244{
1245 bool fRc;
1246 if (iBit < 64)
1247 {
1248#if ARCH_BITS >= 64
1249 fRc = RT_BOOL(pValueResult->s.Lo & RT_BIT_64(iBit));
1250#else
1251 if (iBit < 32)
1252 fRc = RT_BOOL(pValueResult->DWords.dw0 & RT_BIT_32(iBit));
1253 else
1254 fRc = RT_BOOL(pValueResult->DWords.dw1 & RT_BIT_32(iBit - 32));
1255#endif
1256 }
1257 else if (iBit < 128)
1258 {
1259#if ARCH_BITS >= 64
1260 fRc = RT_BOOL(pValueResult->s.Hi & RT_BIT_64(iBit - 64));
1261#else
1262 if (iBit < 96)
1263 fRc = RT_BOOL(pValueResult->DWords.dw2 & RT_BIT_32(iBit - 64));
1264 else
1265 fRc = RT_BOOL(pValueResult->DWords.dw3 & RT_BIT_32(iBit - 96));
1266#endif
1267 }
1268 else
1269 fRc = false;
1270 return fRc;
1271}
1272
1273
1274/**
1275 * Set a range of bits a 128-bit unsigned integer value.
1276 *
1277 * @returns pValueResult.
1278 * @param pValueResult The input and output value.
1279 * @param iFirstBit The first bit to test.
1280 * @param cBits The number of bits to set.
1281 */
1282DECLINLINE(PRTUINT128U) RTUInt128BitSetRange(PRTUINT128U pValueResult, unsigned iFirstBit, unsigned cBits)
1283{
1284 /* bounds check & fix. */
1285 if (iFirstBit < 128)
1286 {
1287 if (iFirstBit + cBits > 128)
1288 cBits = 128 - iFirstBit;
1289
1290#if ARCH_BITS >= 64
1291 if (iFirstBit + cBits < 64)
1292 pValueResult->s.Lo |= (RT_BIT_64(cBits) - 1) << iFirstBit;
1293 else if (iFirstBit + cBits < 128 && iFirstBit >= 64)
1294 pValueResult->s.Hi |= (RT_BIT_64(cBits) - 1) << (iFirstBit - 64);
1295 else
1296#else
1297 if (iFirstBit + cBits < 32)
1298 pValueResult->DWords.dw0 |= (RT_BIT_32(cBits) - 1) << iFirstBit;
1299 else if (iFirstBit + cBits < 64 && iFirstBit >= 32)
1300 pValueResult->DWords.dw1 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 32);
1301 else if (iFirstBit + cBits < 96 && iFirstBit >= 64)
1302 pValueResult->DWords.dw2 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 64);
1303 else if (iFirstBit + cBits < 128 && iFirstBit >= 96)
1304 pValueResult->DWords.dw3 |= (RT_BIT_32(cBits) - 1) << (iFirstBit - 96);
1305 else
1306#endif
1307 while (cBits-- > 0)
1308 RTUInt128BitSet(pValueResult, iFirstBit++);
1309 }
1310 return pValueResult;
1311}
1312
1313
1314/**
1315 * Test if all the bits of a 128-bit unsigned integer value are set.
1316 *
1317 * @returns true if they are, false if they aren't.
1318 * @param pValue The input and output value.
1319 */
1320DECLINLINE(bool) RTUInt128BitAreAllSet(PRTUINT128U pValue)
1321{
1322#if ARCH_BITS >= 64
1323 return pValue->s.Hi == UINT64_MAX
1324 && pValue->s.Lo == UINT64_MAX;
1325#else
1326 return pValue->DWords.dw0 == UINT32_MAX
1327 && pValue->DWords.dw1 == UINT32_MAX
1328 && pValue->DWords.dw2 == UINT32_MAX
1329 && pValue->DWords.dw3 == UINT32_MAX;
1330#endif
1331}
1332
1333
1334/**
1335 * Test if all the bits of a 128-bit unsigned integer value are clear.
1336 *
1337 * @returns true if they are, false if they aren't.
1338 * @param pValue The input and output value.
1339 */
1340DECLINLINE(bool) RTUInt128BitAreAllClear(PRTUINT128U pValue)
1341{
1342#if ARCH_BITS >= 64
1343 return pValue->s.Hi == 0
1344 && pValue->s.Lo == 0;
1345#else
1346 return pValue->DWords.dw0 == 0
1347 && pValue->DWords.dw1 == 0
1348 && pValue->DWords.dw2 == 0
1349 && pValue->DWords.dw3 == 0;
1350#endif
1351}
1352
1353
1354/**
1355 * Number of significant bits in the value.
1356 *
1357 * This is the same a ASMBitLastSetU64 and ASMBitLastSetU32.
1358 *
1359 * @returns 0 if zero, 1-base index of the last bit set.
1360 * @param pValue The value to examine.
1361 */
1362DECLINLINE(uint32_t) RTUInt128BitCount(PCRTUINT128U pValue)
1363{
1364 uint32_t cBits;
1365 if (pValue->s.Hi != 0)
1366 {
1367 if (pValue->DWords.dw3)
1368 cBits = 96 + ASMBitLastSetU32(pValue->DWords.dw3);
1369 else
1370 cBits = 64 + ASMBitLastSetU32(pValue->DWords.dw2);
1371 }
1372 else
1373 {
1374 if (pValue->DWords.dw1)
1375 cBits = 32 + ASMBitLastSetU32(pValue->DWords.dw1);
1376 else
1377 cBits = 0 + ASMBitLastSetU32(pValue->DWords.dw0);
1378 }
1379 return cBits;
1380}
1381
1382
1383/**
1384 * Divides a 128-bit unsigned integer value by another, returning both quotient
1385 * and remainder.
1386 *
1387 * @returns pQuotient, NULL if pValue2 is 0.
1388 * @param pQuotient Where to return the quotient.
1389 * @param pRemainder Where to return the remainder.
1390 * @param pValue1 The dividend value.
1391 * @param pValue2 The divisor value.
1392 */
1393DECLINLINE(PRTUINT128U) RTUInt128DivRem(PRTUINT128U pQuotient, PRTUINT128U pRemainder, PCRTUINT128U pValue1, PCRTUINT128U pValue2)
1394{
1395 int iDiff;
1396
1397 /*
1398 * Sort out all the special cases first.
1399 */
1400 /* Divide by zero or 1? */
1401 if (!pValue2->s.Hi)
1402 {
1403 if (!pValue2->s.Lo)
1404 {
1405 RTUInt128SetZero(pRemainder);
1406 RTUInt128SetZero(pQuotient);
1407 return NULL;
1408 }
1409
1410 if (pValue2->s.Lo == 1)
1411 {
1412 RTUInt128SetZero(pRemainder);
1413 *pQuotient = *pValue1;
1414 return pQuotient;
1415 }
1416 /** @todo RTUint128DivModBy64 */
1417 }
1418
1419 /* Dividend is smaller? */
1420 iDiff = RTUInt128Compare(pValue1, pValue2);
1421 if (iDiff < 0)
1422 {
1423 *pRemainder = *pValue1;
1424 RTUInt128SetZero(pQuotient);
1425 }
1426
1427 /* The values are equal? */
1428 else if (iDiff == 0)
1429 {
1430 RTUInt128SetZero(pRemainder);
1431 RTUInt128AssignU64(pQuotient, 1);
1432 }
1433 else
1434 {
1435 /*
1436 * Prepare.
1437 */
1438 uint32_t iBitAdder = RTUInt128BitCount(pValue1) - RTUInt128BitCount(pValue2);
1439 RTUINT128U NormDivisor = *pValue2;
1440 if (iBitAdder)
1441 {
1442 RTUInt128ShiftLeft(&NormDivisor, pValue2, iBitAdder);
1443 if (RTUInt128IsLarger(&NormDivisor, pValue1))
1444 {
1445 RTUInt128AssignShiftRight(&NormDivisor, 1);
1446 iBitAdder--;
1447 }
1448 }
1449 else
1450 NormDivisor = *pValue2;
1451
1452 RTUInt128SetZero(pQuotient);
1453 *pRemainder = *pValue1;
1454
1455 /*
1456 * Do the division.
1457 */
1458 if (RTUInt128IsLargerOrEqual(pRemainder, pValue2))
1459 {
1460 for (;;)
1461 {
1462 if (RTUInt128IsLargerOrEqual(pRemainder, &NormDivisor))
1463 {
1464 RTUInt128AssignSub(pRemainder, &NormDivisor);
1465 RTUInt128AssignOrBit(pQuotient, iBitAdder);
1466 }
1467 if (RTUInt128IsSmaller(pRemainder, pValue2))
1468 break;
1469 RTUInt128AssignShiftRight(&NormDivisor, 1);
1470 iBitAdder--;
1471 }
1472 }
1473 }
1474 return pQuotient;
1475}
1476
1477
1478/** @} */
1479
1480RT_C_DECLS_END
1481
1482#endif /* !IPRT_INCLUDED_uint128_h */
1483
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use