xref: /php-src/ext/random/php_random_uint128.h (revision 45f8cfaf)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Tim Düsterhus <timwolla@php.net>                            |
14    |          Go Kudo <zeriyoshi@php.net>                                 |
15    |                                                                      |
16    | Based on code from: Melissa O'Neill <oneill@pcg-random.org>          |
17    +----------------------------------------------------------------------+
18 */
19 
20 #ifndef PHP_RANDOM_UINT128_H
21 # define PHP_RANDOM_UINT128_H
22 
23 # include <stdint.h>
24 
25 # if !defined(__SIZEOF_INT128__) || defined(PHP_RANDOM_FORCE_EMULATE_128)
26 typedef struct _php_random_uint128_t {
27 	uint64_t hi;
28 	uint64_t lo;
29 } php_random_uint128_t;
30 
php_random_uint128_hi(php_random_uint128_t num)31 static inline uint64_t php_random_uint128_hi(php_random_uint128_t num)
32 {
33 	return num.hi;
34 }
35 
php_random_uint128_lo(php_random_uint128_t num)36 static inline uint64_t php_random_uint128_lo(php_random_uint128_t num)
37 {
38 	return num.lo;
39 }
40 
php_random_uint128_constant(uint64_t hi,uint64_t lo)41 static inline php_random_uint128_t php_random_uint128_constant(uint64_t hi, uint64_t lo)
42 {
43 	php_random_uint128_t r;
44 
45 	r.hi = hi;
46 	r.lo = lo;
47 
48 	return r;
49 }
50 
php_random_uint128_add(php_random_uint128_t num1,php_random_uint128_t num2)51 static inline php_random_uint128_t php_random_uint128_add(php_random_uint128_t num1, php_random_uint128_t num2)
52 {
53 	php_random_uint128_t r;
54 
55 	r.lo = (num1.lo + num2.lo);
56 	r.hi = (num1.hi + num2.hi + (r.lo < num1.lo));
57 
58 	return r;
59 }
60 
php_random_uint128_multiply(php_random_uint128_t num1,php_random_uint128_t num2)61 static inline php_random_uint128_t php_random_uint128_multiply(php_random_uint128_t num1, php_random_uint128_t num2)
62 {
63 	php_random_uint128_t r;
64 	const uint64_t
65 		x0 = num1.lo & 0xffffffffULL,
66 		x1 = num1.lo >> 32,
67 		y0 = num2.lo & 0xffffffffULL,
68 		y1 = num2.lo >> 32,
69 		z0 = (((x1 * y0) + (x0 * y0 >> 32)) & 0xffffffffULL) + x0 * y1;
70 
71 	r.hi = num1.hi * num2.lo + num1.lo * num2.hi;
72 	r.lo = num1.lo * num2.lo;
73 	r.hi += x1 * y1 + ((x1 * y0 + (x0 * y0 >> 32)) >> 32) + (z0 >> 32);
74 
75 	return r;
76 }
77 
php_random_pcgoneseq128xslrr64_rotr64(php_random_uint128_t num)78 static inline uint64_t php_random_pcgoneseq128xslrr64_rotr64(php_random_uint128_t num)
79 {
80 	const uint64_t
81 		v = (num.hi ^ num.lo),
82 		s = num.hi >> 58U;
83 
84 	return (v >> s) | (v << ((-s) & 63));
85 }
86 # else
87 typedef __uint128_t php_random_uint128_t;
88 
php_random_uint128_hi(php_random_uint128_t num)89 static inline uint64_t php_random_uint128_hi(php_random_uint128_t num)
90 {
91 	return (uint64_t) (num >> 64);
92 }
93 
php_random_uint128_lo(php_random_uint128_t num)94 static inline uint64_t php_random_uint128_lo(php_random_uint128_t num)
95 {
96 	return (uint64_t) num;
97 }
98 
php_random_uint128_constant(uint64_t hi,uint64_t lo)99 static inline php_random_uint128_t php_random_uint128_constant(uint64_t hi, uint64_t lo)
100 {
101 	php_random_uint128_t r;
102 
103 	r = ((php_random_uint128_t) hi << 64) + lo;
104 
105 	return r;
106 }
107 
php_random_uint128_add(php_random_uint128_t num1,php_random_uint128_t num2)108 static inline php_random_uint128_t php_random_uint128_add(php_random_uint128_t num1, php_random_uint128_t num2)
109 {
110 	return num1 + num2;
111 }
112 
php_random_uint128_multiply(php_random_uint128_t num1,php_random_uint128_t num2)113 static inline php_random_uint128_t php_random_uint128_multiply(php_random_uint128_t num1, php_random_uint128_t num2)
114 {
115 	return num1 * num2;
116 }
117 
php_random_pcgoneseq128xslrr64_rotr64(php_random_uint128_t num)118 static inline uint64_t php_random_pcgoneseq128xslrr64_rotr64(php_random_uint128_t num)
119 {
120 	const uint64_t
121 		v = ((uint64_t) (num >> 64U)) ^ (uint64_t) num,
122 		s = num >> 122U;
123 
124 	return (v >> s) | (v << ((-s) & 63));
125 }
126 # endif
127 
128 #endif	/* PHP_RANDOM_UINT128_H */
129