00001 00002 /* 00003 The Extended Integer (XInt) Library 00004 A fast, portable C++ library for multi-precision integer math 00005 Copyright 2010 by Chad Nelson 00006 00007 Distributed under the Boost Software License, Version 1.0. 00008 See accompanying file LICENSE_1_0.txt or copy at 00009 http://www.boost.org/LICENSE_1_0.txt 00010 00011 See http://www.boost.org/libs/xint for library home page. 00012 */ 00013 00020 #ifndef BOOST_INCLUDED_XINT_POLICY_HPP 00021 #define BOOST_INCLUDED_XINT_POLICY_HPP 00022 00023 namespace boost { 00024 namespace xint { 00025 namespace detail { 00027 00029 // Allocation 00030 00031 struct realloc { 00032 enum strategy { ignore, zero, copy, extend }; 00033 }; 00034 00035 template <bitsize_t Bits, bool Secure, class Alloc> 00036 class allocator_t { 00037 BOOST_STATIC_ASSERT(sizeof(typename Alloc::value_type) == sizeof(digit_t)); 00038 00039 public: 00040 static magnitude_t *alloc(std::size_t size, bool readonly = false); 00041 static magnitude_t *realloc_and_uniquify(magnitude_t *old, std::size_t 00042 newsize = 0, realloc::strategy strategy = realloc::copy); 00043 static magnitude_t *duplicate(magnitude_t *source, std::size_t newsize = 0); 00044 static void dealloc(magnitude_t *p); 00045 00046 static void attach(magnitude_t *p); 00047 static void detach(magnitude_t *p); 00048 00049 private: 00050 static Alloc allocator; 00051 static const std::size_t fixed_length; 00052 static const std::size_t magnitude_datasize; 00053 }; 00054 00055 template <bitsize_t Bits, bool Secure, class Alloc> 00056 Alloc allocator_t<Bits, Secure, Alloc>::allocator; 00057 template <bitsize_t Bits, bool Secure, class Alloc> 00058 const std::size_t allocator_t<Bits, Secure, Alloc>::fixed_length = (Bits + 00059 bits_per_digit - 1) / bits_per_digit; 00060 template <bitsize_t Bits, bool Secure, class Alloc> 00061 const std::size_t allocator_t<Bits, Secure, Alloc>::magnitude_datasize = 00062 (sizeof(magnitude_t) + sizeof(digit_t) - 1) / sizeof(digit_t); 00063 00065 // Fixed- or variable-length 00066 00067 template <bitsize_t Bits, bitsize_t Modded = Bits % bits_per_digit> 00068 class fixedlength_t { 00069 public: 00070 static void trim(magnitude_t *p) { 00071 // Only valid if Bits % bits_per_digit is non-zero. 00072 p->digits[last_digit] &= mask; 00073 } 00074 00075 private: 00076 static const std::size_t last_digit; 00077 static const digit_t mask; 00078 }; 00079 00080 template <bitsize_t Bits, bitsize_t Modded> 00081 const std::size_t fixedlength_t<Bits, Modded>::last_digit = ((Bits + 00082 bits_per_digit - 1) / bits_per_digit) - 1; 00083 template <bitsize_t Bits, bitsize_t Modded> 00084 const digit_t fixedlength_t<Bits, Modded>::mask = digit_t((doubledigit_t(1) << 00085 (Bits % bits_per_digit)) - 1); 00086 00087 template <bitsize_t Bits> 00088 class fixedlength_t<Bits, 0> { 00089 public: 00090 static void trim(magnitude_t*) { } 00091 }; 00092 00094 // Function Definitions 00095 00096 template <bitsize_t Bits, bool Secure, class Alloc> 00097 magnitude_t *allocator_t<Bits, Secure, Alloc>::alloc(std::size_t size, bool 00098 readonly) 00099 { 00100 if (fixed_length) size = fixed_length; 00101 else if (size < minimum_digits) size = minimum_digits; 00102 const std::size_t count = size - minimum_digits + magnitude_datasize; 00103 00104 digit_t *storage = 0; 00105 BOOST_XINT_TRY { 00106 storage = allocator.allocate(count); 00107 if (readonly) return new(storage) magnitude_t(size, readonly, 0); 00108 else return new(storage) magnitude_t(size, readonly); 00109 } BOOST_XINT_CATCH_BADALLOC { 00110 exception_handler<>::call(__FILE__, __LINE__, 00111 exceptions::overflow_error("Out of memory allocating integer")); 00112 } BOOST_XINT_CATCH_E { 00113 // To make it exception-safe, we've got to ensure that the allocated 00114 // data is properly disposed of if there's an exception, before passing 00115 // the exception on. 00116 if (storage) allocator.deallocate(storage, size); 00117 exception_handler<>::call(__FILE__, __LINE__, e); 00118 } 00119 00120 // It will never get here, but the compilers can't tell that. 00121 return 0; 00122 } 00123 00124 template <bitsize_t Bits, bool Secure, class Alloc> 00125 magnitude_t *allocator_t<Bits, Secure, Alloc>::realloc_and_uniquify(magnitude_t 00126 *old, std::size_t newsize, realloc::strategy strategy) 00127 { 00128 if (fixed_length) { 00129 newsize = fixed_length; 00130 } else if (newsize == 0) { 00131 if (old) newsize = old->max_length; 00132 else newsize = minimum_digits; 00133 } else if (newsize < minimum_digits) newsize = minimum_digits; 00134 00135 magnitude_t *r = old; 00136 if (old == 0 || newsize > old->max_length || old->copies() > 1) { 00137 r = alloc(newsize); 00138 attach(r); 00139 00140 if (strategy == realloc::ignore) { 00141 // Do nothing. 00142 } else if ((strategy == realloc::extend || strategy == realloc::copy) && 00143 old != 0) 00144 { 00145 const digit_t *s = old->digits, *se = s + old->max_length; 00146 digit_t *t = r->digits, *te = t + r->max_length; 00147 while (s != se && t != te) *t++ = *s++; 00148 } else { 00149 // It's realloc::zero, old == 0. Zero it. 00150 digit_t *t = r->digits, *te = t + r->max_length; 00151 while (t != te) *t++ = 0; 00152 } 00153 00154 detach(old); 00155 } else if (strategy == realloc::zero) { 00156 digit_t *t = r->digits, *te = t + r->max_length; 00157 while (t != te) *t++ = 0; 00158 } 00159 00160 return r; 00161 } 00162 00163 template <bitsize_t Bits, bool Secure, class Alloc> 00164 magnitude_t *allocator_t<Bits, Secure, Alloc>::duplicate(magnitude_t *source, 00165 std::size_t newsize) 00166 { 00167 attach(source); 00168 return realloc_and_uniquify(source, newsize, realloc::copy); 00169 } 00170 00171 template <bitsize_t Bits, bool Secure, class Alloc> 00172 void allocator_t<Bits, Secure, Alloc>::dealloc(magnitude_t *data) { 00173 if (data == 0) return; 00174 00175 const std::size_t len = (data->max_length + magnitude_datasize - 00176 minimum_digits); 00177 00178 // Since the data was initialized with placement-new, we have to manually 00179 // call the destructor. 00180 data-> ~magnitude_t(); 00181 00182 // Finally, dispose of it. 00183 digit_t *p = reinterpret_cast<digit_t*>(data); 00184 if (Secure) memset(p, 0, len * sizeof(digit_t)); 00185 allocator.deallocate(p, len); 00186 } 00187 00188 template <bitsize_t Bits, bool Secure, class Alloc> 00189 void allocator_t<Bits, Secure, Alloc>::attach(magnitude_t *p) { 00190 p->inc(); 00191 } 00192 00193 template <bitsize_t Bits, bool Secure, class Alloc> 00194 void allocator_t<Bits, Secure, Alloc>::detach(magnitude_t *p) { 00195 if (p->dec()) dealloc(p); 00196 } 00197 00199 } // namespace detail 00200 } // namespace xint 00201 } // namespace boost 00202 00203 #endif // BOOST_INCLUDED_XINT_POLICY_HPP
© Copyright Chad Nelson, 2010-2011. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)