1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of TokuDB |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | TokuDBis is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | TokuDB is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with TokuDB. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ======= */ |
23 | |
24 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
25 | |
26 | #if !defined(_TOKUDB_MATH_H) |
27 | #define _TOKUDB_MATH_H |
28 | |
29 | namespace tokudb { |
30 | |
31 | // Add and subtract ints with overflow detection. |
32 | // Overflow detection adapted from "Hackers Delight", Henry S. Warren |
33 | |
34 | // Return a bit mask for bits 0 .. length_bits-1 |
35 | TOKUDB_UNUSED(static uint64_t uint_mask(uint length_bits)); |
36 | static uint64_t uint_mask(uint length_bits) { |
37 | return length_bits == 64 ? ~0ULL : (1ULL<<length_bits)-1; |
38 | } |
39 | |
40 | // Return the highest unsigned int with a given number of bits |
41 | TOKUDB_UNUSED(static uint64_t uint_high_endpoint(uint length_bits)); |
42 | static uint64_t uint_high_endpoint(uint length_bits) { |
43 | return uint_mask(length_bits); |
44 | } |
45 | |
46 | // Return the lowest unsigned int with a given number of bits |
47 | TOKUDB_UNUSED(static uint64_t uint_low_endpoint(uint length_bits)); |
48 | static uint64_t uint_low_endpoint(TOKUDB_UNUSED(uint length_bits)) { |
49 | return 0; |
50 | } |
51 | |
52 | // Add two unsigned integers with max maximum value. |
53 | // If there is an overflow then set the sum to the max. |
54 | // Return the sum and the overflow. |
55 | TOKUDB_UNUSED(static uint64_t uint_add( |
56 | uint64_t x, |
57 | uint64_t y, |
58 | uint length_bits, |
59 | bool* over)); |
60 | static uint64_t uint_add(uint64_t x, uint64_t y, uint length_bits, bool *over) { |
61 | uint64_t mask = uint_mask(length_bits); |
62 | assert_always((x & ~mask) == 0 && (y & ~mask) == 0); |
63 | uint64_t s = (x + y) & mask; |
64 | *over = s < x; // check for overflow |
65 | return s; |
66 | } |
67 | |
68 | // Subtract two unsigned ints with max maximum value. |
69 | // If there is an over then set the difference to 0. |
70 | // Return the difference and the overflow. |
71 | TOKUDB_UNUSED(static uint64_t uint_sub( |
72 | uint64_t x, |
73 | uint64_t y, |
74 | uint length_bits, |
75 | bool* over)); |
76 | static uint64_t uint_sub(uint64_t x, uint64_t y, uint length_bits, bool *over) { |
77 | uint64_t mask = uint_mask(length_bits); |
78 | assert_always((x & ~mask) == 0 && (y & ~mask) == 0); |
79 | uint64_t s = (x - y) & mask; |
80 | *over = s > x; // check for overflow |
81 | return s; |
82 | } |
83 | |
84 | // Return the highest int with a given number of bits |
85 | TOKUDB_UNUSED(static int64_t int_high_endpoint(uint length_bits)); |
86 | static int64_t int_high_endpoint(uint length_bits) { |
87 | return (1ULL<<(length_bits-1))-1; |
88 | } |
89 | |
90 | // Return the lowest int with a given number of bits |
91 | TOKUDB_UNUSED(static int64_t int_low_endpoint(uint length_bits)); |
92 | static int64_t int_low_endpoint(uint length_bits) { |
93 | int64_t mask = uint_mask(length_bits); |
94 | return (1ULL<<(length_bits-1)) | ~mask; |
95 | } |
96 | |
97 | // Sign extend to 64 bits an int with a given number of bits |
98 | TOKUDB_UNUSED(static int64_t int_sign_extend(int64_t n, uint length_bits)); |
99 | static int64_t int_sign_extend(int64_t n, uint length_bits) { |
100 | if (n & (1ULL<<(length_bits-1))) |
101 | n |= ~uint_mask(length_bits); |
102 | return n; |
103 | } |
104 | |
105 | // Add two signed ints with max maximum value. |
106 | // If there is an overflow then set the sum to the max or the min of the int range, |
107 | // depending on the sign bit. |
108 | // Sign extend to 64 bits. |
109 | // Return the sum and the overflow. |
110 | TOKUDB_UNUSED(static int64_t int_add( |
111 | int64_t x, |
112 | int64_t y, |
113 | uint length_bits, |
114 | bool* over)); |
115 | static int64_t int_add(int64_t x, int64_t y, uint length_bits, bool *over) { |
116 | int64_t mask = uint_mask(length_bits); |
117 | int64_t n = (x + y) & mask; |
118 | *over = (((n ^ x) & (n ^ y)) >> (length_bits-1)) & 1; // check for overflow |
119 | if (n & (1LL<<(length_bits-1))) |
120 | n |= ~mask; // sign extend |
121 | return n; |
122 | } |
123 | |
124 | // Subtract two signed ints. |
125 | // If there is an overflow then set the sum to the max or the min of the int range, |
126 | // depending on the sign bit. |
127 | // Sign extend to 64 bits. |
128 | // Return the sum and the overflow. |
129 | TOKUDB_UNUSED(static int64_t int_sub( |
130 | int64_t x, |
131 | int64_t y, |
132 | uint length_bits, |
133 | bool* over)); |
134 | static int64_t int_sub(int64_t x, int64_t y, uint length_bits, bool *over) { |
135 | int64_t mask = uint_mask(length_bits); |
136 | int64_t n = (x - y) & mask; |
137 | *over = (((x ^ y) & (n ^ x)) >> (length_bits-1)) & 1; // check for overflow |
138 | if (n & (1LL<<(length_bits-1))) |
139 | n |= ~mask; // sign extend |
140 | return n; |
141 | } |
142 | |
143 | } // namespace tokudb |
144 | |
145 | #endif |
146 | |