1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-16 07:07:13 +02:00

Dumped the old implementation. Started with a more simple approach.

This commit is contained in:
Sandu Liviu Catalin
2016-02-21 00:25:00 +02:00
parent 96ded94026
commit 06e598acfb
293 changed files with 37439 additions and 92564 deletions

View File

@ -1,149 +0,0 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
Several funtions are included here, forming a complete set of
conversions between the three formats. UTF-7 is not included
here, but is handled in a separate source file.
Each of these routines takes pointers to input buffers and output
buffers. The input buffers are const.
Each routine converts the text between *sourceStart and sourceEnd,
putting the result into the buffer between *targetStart and
targetEnd. Note: the end pointers are *after* the last item: e.g.
*(sourceEnd - 1) is the last item.
The return result indicates whether the conversion was successful,
and if not, whether the problem was in the source or target buffers.
(Only the first encountered problem is indicated.)
After the conversion, *sourceStart and *targetStart are both
updated to point to the end of last text successfully converted in
the respective buffers.
Input parameters:
sourceStart - pointer to a pointer to the source buffer.
The contents of this are modified on return so that
it points at the next thing to be converted.
targetStart - similarly, pointer to pointer to the target buffer.
sourceEnd, targetEnd - respectively pointers to the ends of the
two buffers, for overflow checking only.
These conversion functions take a ConversionFlags argument. When this
flag is set to strict, both irregular sequences and isolated surrogates
will cause an error. When the flag is set to lenient, both irregular
sequences and isolated surrogates are converted.
Whether the flag is strict or lenient, all illegal sequences will cause
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
must check for illegal sequences.
When the flag is set to lenient, characters over 0x10FFFF are converted
to the replacement character; otherwise (when the flag is set to strict)
they constitute an error.
Output parameters:
The value "sourceIllegal" is returned from some routines if the input
sequence is malformed. When "sourceIllegal" is returned, the source
value will point to the illegal value that caused the problem. E.g.,
in UTF-8 when a sequence is malformed, it points to the start of the
malformed sequence.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
16 bits, so wchar_t is no less portable than unsigned short!
All should be unsigned values to avoid sign extension during
bit mask & shift operations.
------------------------------------------------------------------------ */
typedef unsigned int UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
typedef unsigned char Boolean; /* 0 or 1 */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
#define UNI_MAX_BMP (UTF32)0x0000FFFF
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum {
strictConversion = 0,
lenientConversion
} ConversionFlags;
/* This is for C++ and does no harm in C */
#ifdef __cplusplus
extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF8toUTF32 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF16 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
#ifdef __cplusplus
}
#endif
/* --------------------------------------------------------------------- */

View File

@ -0,0 +1,13 @@
#define RANDOMLIB_VERSION_STRING "Unconfigured"
#define RANDOMLIB_VERSION_MAJOR -1
#define RANDOMLIB_VERSION_MINOR -1
#define RANDOMLIB_VERSION_PATCH -1
// Define HAVE_SSE2 to be 1 if Intel/AMD CPU with SSE2 support
/* #undef HAVE_SSE2 */
// Define HAVE_ALTIVEC to be 1 if Power PC CPU with AltiVec support
/* #undef HAVE_ALTIVEC */
// Undefine HAVE_LONG_DOUBLE if this type is unknown to the compiler
#define HAVE_LONG_DOUBLE 1

View File

@ -0,0 +1,432 @@
/**
* \file DiscreteNormal.hpp
* \brief Header for DiscreteNormal
*
* Sample exactly from the discrete normal distribution.
*
* Copyright (c) Charles Karney (2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_DISCRETENORMAL_HPP)
#define RANDOMLIB_DISCRETENORMAL_HPP 1
#include <vector>
#include <limits>
namespace RandomLib {
/**
* \brief The discrete normal distribution.
*
* Sample integers \e i with probability proportional to
* \f[
* \exp\biggl[-\frac12\biggl(\frac{i-\mu}{\sigma}\biggr)^2\biggr],
* \f]
* where &sigma; and &mu; are given as rationals (the ratio of two integers).
* The sampling is exact (provided that the random generator is ideal). For
* example
* \code
#include <iostream>
#include <RandomLib/Random.hpp>
#include <RandomLib/DiscreteNormal.hpp>
int main() {
RandomLib::Random r; // Create r
r.Reseed(); // and give it a unique seed
int sigma_num = 7, sigma_den = 1, mu_num = 1, mu_den = 3;
RandomLib::DiscreteNormal<int> d(sigma_num, sigma_den,
mu_num, mu_den);
for (int i = 0; i < 100; ++i)
std::cout << d(r) << "\n";
}
\endcode
* prints out 100 samples with &sigma; = 7 and &mu; = 1/3.
*
* The algorithm is much the same as for ExactNormal; for details see
* - C. F. F. Karney, <i>Sampling exactly from the normal distribution</i>,
* http://arxiv.org/abs/1303.6257 (Mar. 2013).
* .
* That algorithm samples the integer part of the result \e k, samples \e x
* in [0,1], and (unless rejected) returns <i>s</i>(\e k + \e x), where \e s
* = &plusmn;1. For the discrete case, we sample \e x in [0,1) such that
* \f[
* s(k + x) = (i - \mu)/\sigma,
* \f]
* or
* \f[
* x = s(i - \mu)/\sigma - k
* \f]
* The value of \e i which results in the smallest \e x &ge; 0 is
* \f[
* i_0 = s\lceil k \sigma + s \mu\rceil
* \f]
* so sample
* \f[
* i = i_0 + sj
* \f]
* where \e j is uniformly distributed in [0, &lceil;&sigma;&rceil;). The
* corresponding value of \e x is
* \f[
* \begin{aligned}
* x &= \bigl(si_0 - (k\sigma + s\mu)\bigr)/\sigma + j/\sigma\\
* &= x_0 + j/\sigma,\\
* x_0 &= \bigl(\lceil k \sigma + s \mu\rceil -
* (k \sigma + s \mu)\bigr)/\sigma.
* \end{aligned}
* \f]
* After \e x is sampled in this way, it should be rejected if \e x &ge; 1
* (this is counted with the next larger value of \e k) or if \e x = 0, \e k
* = 0, and \e s = &minus;1 (to avoid double counting the origin). If \e x
* is accepted (in Step 4 of the ExactNormal algorithm), then return \e i.
*
* When &sigma; and &mu; are given as rationals, all the arithmetic outlined
* above can be carried out exactly. The basic rejection techniques used by
* ExactNormal are exact. Thus the result of this discrete form of the
* algorithm is also exact.
*
* RandomLib provides two classes to sample from this distribution:
* - DiscreteNormal which is tuned for speed on a typical general purpose
* computer. This assumes that random samples can be generated relatively
* quickly.
* - DiscreteNormalAlt, which is a prototype for what might be needed on a
* small device used for cryptography which is using a hardware generator
* for obtaining truly random bits. This assumption here is that the
* random bits are relatively expensive to obtain.
* .
* The basic algorithm is the same in the two cases. The main advantages of
* this method are:
* - exact sampling (provided that the source of random numbers is ideal),
* - no need to cut off the tails of the distribution,
* - a short program involving simple integer operations only,
* - no dependence on external libraries (except to generate random bits),
* - no large tables of constants needed,
* - minimal time to set up for a new &sigma; and &mu; (roughly comparable to
* the time it takes to generate one sample),
* - only about 5&ndash;20 times slower than standard routines to sample from
* a normal distribution using plain double-precision arithmetic.
* - DiscreteNormalAlt exhibits ideal scaling for the consumption of random
* bits, namely a constant + log<sub>2</sub>&sigma;, for large &sigma;,
* where the constant is about 31.
* .
* The possible drawbacks of this method are:
* - &sigma; and &mu; are restricted to rational numbers with sufficiently
* small numerators and denominators to avoid overflow (this is unlikely to
* be a severe restriction especially if the template parameter IntType is
* set to <code>long long</code>),
* - the running time is unbounded (but not in any practical sense),
* - the memory consumption is unbounded (but not in any practical sense),
* - the toll, about 30 bits, is considerably worse than that obtained using
* the Knuth-Yao algorithm, for which the toll is no more than 2 (but this
* requires a large table which is expensive to compute and requires a lot
* of memory to store).
*
* This class uses a mutable private vector. So a single DiscreteNormal
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific DiscreteNormal
* object.
*
* Some timing results for IntType = int, &mu; = 0, and 10<sup>8</sup>
* samples (time = time per sample, including setup time, rv = mean number of
* random variables per sample)
* - &sigma; = 10, time = 219 ns, rv = 17.52
* - &sigma; = 32, time = 223 ns, rv = 17.82
* - &sigma; = 1000, time = 225 ns, rv = 17.95
* - &sigma; = 160000, time = 226 ns, rv = 17.95
*
* @tparam IntType the integer type to use (default int).
**********************************************************************/
template<typename IntType = int> class DiscreteNormal {
public:
/**
* Constructor.
*
* @param[in] sigma_num the numerator of &sigma;.
* @param[in] sigma_den the denominator of &sigma; (default 1).
* @param[in] mu_num the numerator of &mu; (default 0).
* @param[in] mu_den the denominator of &mu; (default 1).
*
* The constructor creates a DiscreteNormal objects for sampling with
* specific values of &sigma; and &mu;. This may throw an exception if the
* parameters are such that overflow is possible. Internally &sigma; and
* &mu; are expressed with a common denominator, so it may be possible to
* avoid overflow by picking the fractions of these quantities so that \e
* sigma_den and \e mu_den have many common factors.
**********************************************************************/
DiscreteNormal(IntType sigma_num, IntType sigma_den = 1,
IntType mu_num = 0, IntType mu_den = 1);
/**
* Return a sample.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return discrete normal integer.
**********************************************************************/
template<class Random>
IntType operator()(Random& r) const;
private:
/**
* sigma = _sig / _d, mu = _imu + _mu / _d, _isig = floor(sigma)
**********************************************************************/
IntType _sig, _mu, _d, _isig, _imu;
typedef unsigned short word;
/**
* Holds as much of intermediate uniform deviates as needed.
**********************************************************************/
mutable std::vector<word> _v;
mutable unsigned _m, _l;
/**
* Increment on size of _v.
**********************************************************************/
static const unsigned alloc_incr = 16;
// ceil(n/d) for d > 0
static IntType iceil(IntType n, IntType d);
// abs(n) needed because Visual Studio's std::abs has problems
static IntType iabs(IntType n);
static IntType gcd(IntType u, IntType v);
// After x = LeadingDigit(p), p/_sig = (x + p'/_sig)/b where p and p' are
// in [0, _sig) and b = 1 + max(word).
word LeadingDigit(IntType& p) const;
/**
* Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2);
* return:
* - 1 (succeed unconditionally) with prob (\e m &minus; 2) / \e m,
* - 0 (succeed with probability x) with prob 1 / \e m,
* - &minus;1 (fail unconditionally) with prob 1 / \e m.
**********************************************************************/
template<class Random> static int Choose(Random& r, int m);
// Compute v' < v. If true set v = v'.
template<class Random> bool less_than(Random& r) const;
// Compute v < (x + p/_sig)/base (updating v)
template<class Random> bool less_than(Random& r, word x, IntType p) const;
// true with prob (x + p/_sig)/base
template<class Random> bool bernoulli(Random& r, word x, IntType p) const;
/**
* Return true with probability exp(&minus;1/2).
**********************************************************************/
template<class Random> bool ExpProbH(Random& r) const;
/**
* Return true with probability exp(&minus;<i>n</i>/2).
**********************************************************************/
template<class Random> bool ExpProb(Random& r, int n) const;
/**
* Return \e n with probability exp(&minus;<i>n</i>/2)
* (1&minus;exp(&minus;1/2)).
**********************************************************************/
template<class Random> int ExpProbN(Random& r) const;
/**
* Algorithm B: true with prob exp(-x * (2*k + x) / (2*k + 2)) where
* x = (x0 + xn / _sig)/b.
**********************************************************************/
template<class Random>
bool B(Random& r, int k, word x0, IntType xn) const;
};
template<typename IntType> DiscreteNormal<IntType>::DiscreteNormal
(IntType sigma_num, IntType sigma_den,
IntType mu_num, IntType mu_den)
: _v(std::vector<word>(alloc_incr)), _m(0), _l(alloc_incr) {
STATIC_ASSERT(std::numeric_limits<IntType>::is_integer,
"DiscreteNormal: invalid integer type IntType");
STATIC_ASSERT(std::numeric_limits<IntType>::is_signed,
"DiscreteNormal: IntType must be a signed type");
STATIC_ASSERT(!std::numeric_limits<word>::is_signed,
"DiscreteNormal: word must be an unsigned type");
STATIC_ASSERT(std::numeric_limits<IntType>::digits + 1 >=
std::numeric_limits<word>::digits,
"DiscreteNormal: IntType must be at least as wide as word");
if (!( sigma_num > 0 && sigma_den > 0 && mu_den > 0 ))
throw RandomErr("DiscreteNormal: need sigma > 0");
_imu = mu_num / mu_den;
if (_imu == (std::numeric_limits<IntType>::min)())
throw RandomErr("DiscreteNormal: abs(mu) too large");
mu_num -= _imu * mu_den;
IntType l;
l = gcd(sigma_num, sigma_den); sigma_num /= l; sigma_den /= l;
l = gcd(mu_num, mu_den); mu_num /= l; mu_den /= l;
_isig = iceil(sigma_num, sigma_den);
l = gcd(sigma_den, mu_den);
_sig = sigma_num * (mu_den / l);
_mu = mu_num * (sigma_den / l);
_d = sigma_den * (mu_den / l);
// The rest of the constructor tests for possible overflow
// Check for overflow in computing member variables
IntType maxint = (std::numeric_limits<IntType>::max)();
if (!( mu_den / l <= maxint / sigma_num &&
mu_num <= maxint / (sigma_den / l) &&
mu_den / l <= maxint / sigma_den ))
throw RandomErr("DiscreteNormal: sigma or mu overflow");
// The probability that k = kmax is about 10^-543.
int kmax = 50;
// Check that max plausible result fits in an IntType, i.e.,
// _isig * (kmax + 1) + abs(_imu) does not lead to overflow.
if (!( kmax + 1 <= maxint / _isig &&
_isig * (kmax + 1) <= maxint - iabs(_imu) ))
throw RandomErr("DiscreteNormal: possible overflow a");
// Check xn0 = _sig * k + s * _mu;
if (!( kmax <= maxint / _sig &&
_sig * kmax <= maxint - iabs(_mu) ))
throw RandomErr("DiscreteNormal: possible overflow b");
// Check for overflow in LeadingDigit
// p << bits, p = _sig - 1, bits = 8
if (!( _sig <= (maxint >> 8) ))
throw RandomErr("DiscreteNormal: overflow in LeadingDigit");
}
template<typename IntType> template<class Random>
IntType DiscreteNormal<IntType>::operator()(Random& r) const {
for (;;) {
int k = ExpProbN(r);
if (!ExpProb(r, k * (k - 1))) continue;
IntType
s = r.Boolean() ? -1 : 1,
xn = _sig * IntType(k) + s * _mu,
i = iceil(xn, _d) + r.template Integer<IntType>(_isig);
xn = i * _d - xn;
if (xn >= _sig || (k == 0 && s < 0 && xn <= 0)) continue;
if (xn > 0) {
word x0 = LeadingDigit(xn); // Find first digit in expansion in words
int h = k + 1; while (h-- && B(r, k, x0, xn));
if (!(h < 0)) continue;
}
return s * i + _imu;
}
}
template<typename IntType>
IntType DiscreteNormal<IntType>::iceil(IntType n, IntType d)
{ IntType k = n / d; return k + (k * d < n ? 1 : 0); }
template<typename IntType> IntType DiscreteNormal<IntType>::iabs(IntType n)
{ return n < 0 ? -n : n; }
template<typename IntType>
IntType DiscreteNormal<IntType>::gcd(IntType u, IntType v) {
// Knuth, TAOCP, vol 2, 4.5.2, Algorithm A
u = iabs(u); v = iabs(v);
while (v > 0) { IntType r = u % v; u = v; v = r; }
return u;
}
template<typename IntType> typename DiscreteNormal<IntType>::word
DiscreteNormal<IntType>::LeadingDigit(IntType& p) const {
static const unsigned bits = 8;
static const unsigned num = std::numeric_limits<word>::digits / bits;
STATIC_ASSERT(bits * num == std::numeric_limits<word>::digits,
"Number of digits in word must be multiple of 8");
word s = 0;
for (unsigned c = num; c--;) {
p <<= bits; s <<= bits;
word d = word(p / _sig);
s += d;
p -= IntType(d) * _sig;
}
return s;
}
template<typename IntType> template<class Random>
int DiscreteNormal<IntType>::Choose(Random& r, int m) {
int k = r.template Integer<int>(m);
return k == 0 ? 0 : (k == 1 ? -1 : 1);
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::less_than(Random& r) const {
for (unsigned j = 0; ; ++j) {
if (j == _m) {
// Need more bits in the old V
if (_l == _m) _v.resize(_l += alloc_incr);
_v[_m++] = r.template Integer<word>();
}
word w = r.template Integer<word>();
if (w > _v[j])
return false; // New V is bigger, so exit
else if (w < _v[j]) {
_v[j] = w; // New V is smaller, update _v
_m = j + 1; // adjusting its size
return true; // and generate the next V
}
// Else w == _v[j] and we need to check the next word
}
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::less_than(Random& r, word x, IntType p) const {
if (_m == 0) _v[_m++] = r.template Integer<word>();
if (_v[0] != x) return _v[0] < x;
for (unsigned j = 1; ; ++j) {
if (p == 0) return false;
if (j == _m) {
if (_l == _m) _v.resize(_l += alloc_incr);
_v[_m++] = r.template Integer<word>();
}
x = LeadingDigit(p);
if (_v[j] != x) return _v[j] < x;
}
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::bernoulli(Random& r, word x, IntType p) const {
word w = r.template Integer<word>();
if (w != x) return w < x;
for (;;) {
if (p == 0) return false;
x = LeadingDigit(p);
w = r.template Integer<word>();
if (w != x) return w < x;
}
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::ExpProbH(Random& r) const {
static const word half = word(1) << (std::numeric_limits<word>::digits - 1);
_m = 0;
if ((_v[_m++] = r.template Integer<word>()) & half) return true;
// Here _v < 1/2. Now loop finding decreasing V. Exit when first
// increasing one is found.
for (unsigned s = 0; ; s ^= 1) { // Parity of loop count
if (!less_than(r)) return s != 0u;
}
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::ExpProb(Random& r, int n) const {
while (n-- > 0) { if (!ExpProbH(r)) return false; }
return true;
}
template<typename IntType> template<class Random>
int DiscreteNormal<IntType>::ExpProbN(Random& r) const {
int n = 0;
while (ExpProbH(r)) ++n;
return n;
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::B(Random& r, int k, word x0, IntType xn)
const {
int n = 0, h = 2 * k + 2, f;
_m = 0;
for (;; ++n) {
if ( ((f = k ? 0 : Choose(r, h)) < 0) ||
!(n ? less_than(r) : less_than(r, x0, xn)) ||
((f = k ? Choose(r, h) : f) < 0) ||
(f == 0 && !bernoulli(r, x0, xn)) ) break;
}
return (n % 2) == 0;
}
} // namespace RandomLib
#endif // RANDOMLIB_DISCRETENORMAL_HPP

View File

@ -0,0 +1,328 @@
/**
* \file DiscreteNormalAlt.hpp
* \brief Header for DiscreteNormalAlt
*
* Sample exactly from the discrete normal distribution (alternate version).
*
* Copyright (c) Charles Karney (2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_DISCRETENORMALALT_HPP)
#define RANDOMLIB_DISCRETENORMALALT_HPP 1
#include <RandomLib/RandomNumber.hpp>
#include <RandomLib/UniformInteger.hpp>
#include <limits>
namespace RandomLib {
/**
* \brief The discrete normal distribution (alternate version).
*
* Sample integers \e i with probability proportional to
* \f[
* \exp\biggl[-\frac12\biggl(\frac{i-\mu}{\sigma}\biggr)^2\biggr],
* \f]
* where &sigma; and &mu; are given as rationals (the ratio of two integers).
* The sampling is exact (provided that the random generator is ideal). The
* results of this class are UniformInteger objects which represent a
* contiguous range which is a power of 2<sup>\e bits</sup>. This can be
* narrowed down to a specific integer as follows
* \code
#include <iostream>
#include <RandomLib/Random.hpp>
#include <RandomLib/UniformInteger.hpp>
#include <RandomLib/DiscreteNormalAlt.hpp>
int main() {
RandomLib::Random r; // Create r
r.Reseed(); // and give it a unique seed
int sigma_num = 7, sigma_den = 1, mu_num = 1, mu_den = 3;
RandomLib::DiscreteNormalAlt<int,1> d(sigma_num, sigma_den,
mu_num, mu_den);
for (int i = 0; i < 100; ++i) {
RandomLib::UniformInteger<int,1> u = d(r);
std::cout << u << " = ";
std::cout << u(r) << "\n";
}
}
\endcode
* prints out 100 samples with &sigma; = 7 and &mu; = 1/3; the samples are
* first given as a range and then <code>u(r)</code> is used to obtain a
* specific integer. In some applications, it might be possible to avoid
* sampling all the additional digits to get to a specific integer. (An
* example would be drawing a sample which satisfies an inequality.) This
* version is slower (by a factor of about 4 for \e bits = 1) than
* DiscreteNormal on a conventional computer, but may be faster when random
* bits are generated by a slow hardware device.
*
* The basic algorithm is the same as for DiscreteNormal. However randomness
* in metered out \e bits random bits at a time. The algorithm uses the
* least random bits (and is slowest!) when \e bits = 1. This rationing of
* random bits also applies to sampling \e j in the expression
* \f[
* x = x_0 + j/\sigma.
* \f]
* Rather than sampling a definite value for \e j, which then might be
* rejected, \e j is sampled using UniformInteger. UniformInteger uses
* Lumbroso's method from sampling an integer uniformly in [0, \e m) using at
* most 2 + log<sub>2</sub>\e m bits on average (for \e bits = 1). However
* when a UniformInteger object is first constructed it samples at most 3
* bits (on average) to obtain a range for \e j which is power of 2. This
* allows the algorithm to achieve ideal scaling in the limit of large
* &sigma; consuming constant + log<sub>2</sub>&sigma; bits on average. In
* addition it can deliver the resuls in the form of a UniformInteger
* consuming a constant number of bits on average (and then about
* log<sub>2</sub>&sigma; additional bits are required to convert the
* UniformInteger into an integer sample). The consumption of random bits
* (for \e bits = 1) is summarized here \verbatim
min mean max
bits for UniformInteger result 30.4 34.3 35.7
bits for integer result - log2(sigma) 28.8 31.2 32.5
toll 26.8 29.1 30.4 \endverbatim
* These results are averaged over many samples. The "min" results apply
* when &sigma; is a power of 2; the "max" results apply when &sigma; is
* slightly more than a power of two; the "mean" results are averaged over
* &sigma;. The toll is the excess number of bits over the entropy of the
* distribution, which is log<sub>2</sub>(2&pi;\e e)/2 +
* log<sub>2</sub>&sigma; (for &sigma; large).
*
* The data for the first two lines in the table above are taken for the blue
* and red lines in the figure below where the abscissa is the fractional
* part of log<sub>2</sub>&sigma;
* \image html
* discrete-bits.png "Random bits to sample from discrete normal distribution"
*
* This class uses a mutable RandomNumber objects. So a single
* DiscreteNormalAlt object cannot safely be used by multiple threads. In a
* multi-processing environment, each thread should use a thread-specific
* DiscreteNormalAlt object.
*
* @tparam IntType the integer type to use (default int).
**********************************************************************/
template<typename IntType = int, int bits = 1> class DiscreteNormalAlt {
public:
/**
* Constructor.
*
* @param[in] sigma_num the numerator of &sigma;.
* @param[in] sigma_den the denominator of &sigma; (default 1).
* @param[in] mu_num the numerator of &mu; (default 0).
* @param[in] mu_den the denominator of &mu; (default 1).
*
* This may throw an exception is the parameters are such that overflow is
* possible.
**********************************************************************/
DiscreteNormalAlt(IntType sigma_num, IntType sigma_den = 1,
IntType mu_num = 0, IntType mu_den = 1);
/**
* Return a sample.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return discrete normal sample in the form of a UniformInteger object.
**********************************************************************/
template<class Random>
UniformInteger<IntType, bits> operator()(Random& r) const;
private:
/**
* sigma = _sig / _d, mu = _imu + _mu / _d, _isig = ceil(sigma)
**********************************************************************/
IntType _sig, _mu, _d, _isig, _imu;
mutable RandomNumber<bits> _p;
mutable RandomNumber<bits> _q;
// ceil(n/d) for d > 0
static IntType iceil(IntType n, IntType d);
// abs(n) needed because Visual Studio's std::abs has problems
static IntType iabs(IntType n);
static IntType gcd(IntType u, IntType v);
/**
* Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2);
* return:
* - 1 (succeed unconditionally) with prob (\e m &minus; 2) / \e m,
* - 0 (succeed with probability x) with prob 1 / \e m,
* - &minus;1 (fail unconditionally) with prob 1 / \e m.
**********************************************************************/
template<class Random> static int Choose(Random& r, int m);
/**
* Return true with probability exp(&minus;1/2).
**********************************************************************/
template<class Random> bool ExpProbH(Random& r) const;
/**
* Return true with probability exp(&minus;<i>n</i>/2).
**********************************************************************/
template<class Random> bool ExpProb(Random& r, int n) const;
/**
* Return \e n with probability exp(&minus;<i>n</i>/2)
* (1&minus;exp(&minus;1/2)).
**********************************************************************/
template<class Random> int ExpProbN(Random& r) const;
/**
* Algorithm B: true with prob exp(-x * (2*k + x) / (2*k + 2)) where
* x = (xn0 + _d * j) / _sig
**********************************************************************/
template<class Random>
bool B(Random& r, int k, IntType xn0, UniformInteger<IntType, bits>& j)
const;
};
template<typename IntType, int bits>
DiscreteNormalAlt<IntType, bits>::DiscreteNormalAlt
(IntType sigma_num, IntType sigma_den, IntType mu_num, IntType mu_den) {
STATIC_ASSERT(std::numeric_limits<IntType>::is_integer,
"DiscreteNormalAlt: invalid integer type IntType");
STATIC_ASSERT(std::numeric_limits<IntType>::is_signed,
"DiscreteNormalAlt: IntType must be a signed type");
if (!( sigma_num > 0 && sigma_den > 0 && mu_den > 0 ))
throw RandomErr("DiscreteNormalAlt: need sigma > 0");
_imu = mu_num / mu_den;
if (_imu == (std::numeric_limits<IntType>::min)())
throw RandomErr("DiscreteNormalAlt: abs(mu) too large");
mu_num -= _imu * mu_den;
IntType l;
l = gcd(sigma_num, sigma_den); sigma_num /= l; sigma_den /= l;
l = gcd(mu_num, mu_den); mu_num /= l; mu_den /= l;
_isig = iceil(sigma_num, sigma_den);
l = gcd(sigma_den, mu_den);
_sig = sigma_num * (mu_den / l);
_mu = mu_num * (sigma_den / l);
_d = sigma_den * (mu_den / l);
// The rest of the constructor tests for possible overflow
// Check for overflow in computing member variables
IntType maxint = (std::numeric_limits<IntType>::max)();
if (!( mu_den / l <= maxint / sigma_num &&
iabs(mu_num) <= maxint / (sigma_den / l) &&
mu_den / l <= maxint / sigma_den ))
throw RandomErr("DiscreteNormalAlt: sigma or mu overflow");
if (!UniformInteger<IntType, bits>::Check(_isig, _d))
throw RandomErr("DiscreteNormalAlt: overflow in UniformInteger");
// The probability that k = kmax is about 10^-543.
int kmax = 50;
// Check that max plausible result fits in an IntType, i.e.,
// _isig * (kmax + 1) + abs(_imu) does not lead to overflow.
if (!( kmax + 1 <= maxint / _isig &&
_isig * (kmax + 1) <= maxint - iabs(_imu) ))
throw RandomErr("DiscreteNormalAlt: possible overflow a");
// Check xn0 = _sig * k + s * _mu;
if (!( kmax <= maxint / _sig &&
_sig * kmax <= maxint - iabs(_mu) ))
throw RandomErr("DiscreteNormalAlt: possible overflow b");
// Check for overflow in RandomNumber::LessThan(..., UniformInteger& j)
// p0 * b, p0 = arg2 = xn0 = _d - 1
// c *= b, c = arg3 = _d
// digit(D, k) * q, digit(D, k) = b - 1, q = arg4 = _sig
if (!( _d <= maxint >> bits ))
throw std::runtime_error("DiscreteNormalAlt: overflow in RandomNumber a");
if (!( (IntType(1) << bits) - 1 <= maxint / _sig ))
throw std::runtime_error("DiscreteNormalAlt: overflow in RandomNumber b");
}
template<typename IntType, int bits> template<class Random>
UniformInteger<IntType, bits>
DiscreteNormalAlt<IntType, bits>::operator()(Random& r) const {
for (;;) {
int k = ExpProbN(r);
if (!ExpProb(r, k * (k - 1))) continue;
UniformInteger<IntType, bits> j(r, _isig);
IntType
s = r.Boolean() ? -1 : 1,
xn0 = _sig * IntType(k) + s * _mu,
i0 = iceil(xn0, _d); // i = i0 + j
xn0 = i0 * _d - xn0; // xn = xn0 + _d * j
if (!j.LessThan(r, _sig - xn0, _d) ||
(k == 0 && s < 0 && !j.GreaterThan(r, -xn0, _d))) continue;
int h = k + 1; while (h-- && B(r, k, xn0, j));
if (!(h < 0)) continue;
j.Add(i0 + s * _imu);
if (s < 0) j.Negate();
return j;
}
}
template<typename IntType, int bits>
IntType DiscreteNormalAlt<IntType, bits>::iceil(IntType n, IntType d)
{ IntType k = n / d; return k + (k * d < n ? 1 : 0); }
template<typename IntType, int bits>
IntType DiscreteNormalAlt<IntType, bits>::iabs(IntType n)
{ return n < 0 ? -n : n; }
template<typename IntType, int bits>
IntType DiscreteNormalAlt<IntType, bits>::gcd(IntType u, IntType v) {
// Knuth, TAOCP, vol 2, 4.5.2, Algorithm A
u = iabs(u); v = iabs(v);
while (v > 0) { IntType r = u % v; u = v; v = r; }
return u;
}
template<typename IntType, int bits> template<class Random>
int DiscreteNormalAlt<IntType, bits>::Choose(Random& r, int m) {
// Limit base to 2^15 to avoid integer overflow
const int b = bits > 15 ? 15 : bits;
const unsigned mask = (1u << b) - 1;
int n1 = m - 2, n2 = m - 1;
// Evaluate u < n/m where u is a random real number in [0,1). Write u =
// (d + u') / 2^b where d is a random integer in [0,2^b) and u' is in
// [0,1). Then u < n/m becomes u' < n'/m where n' = 2^b * n - d * m and
// exit if n' <= 0 (false) or n' >= m (true).
for (;;) {
int d = (mask & RandomNumber<bits>::RandomDigit(r)) * m;
n1 = (std::max)((n1 << b) - d, 0);
if (n1 >= m) return 1;
n2 = (std::min)((n2 << b) - d, m);
if (n2 <= 0) return -1;
if (n1 == 0 && n2 == m) return 0;
}
}
template<typename IntType, int bits> template<class Random>
bool DiscreteNormalAlt<IntType, bits>::ExpProbH(Random& r) const {
_p.Init();
if (_p.Digit(r, 0) >> (bits - 1)) return true;
for (;;) {
_q.Init(); if (!_q.LessThan(r, _p)) return false;
_p.Init(); if (!_p.LessThan(r, _q)) return true;
}
}
template<typename IntType, int bits> template<class Random>
bool DiscreteNormalAlt<IntType, bits>::ExpProb(Random& r, int n) const {
while (n-- > 0) { if (!ExpProbH(r)) return false; }
return true;
}
template<typename IntType, int bits> template<class Random>
int DiscreteNormalAlt<IntType, bits>::ExpProbN(Random& r) const {
int n = 0;
while (ExpProbH(r)) ++n;
return n;
}
template<typename IntType, int bits> template<class Random> bool
DiscreteNormalAlt<IntType, bits>::B(Random& r, int k, IntType xn0,
UniformInteger<IntType, bits>& j)
const {
int n = 0, m = 2 * k + 2, f;
for (;; ++n) {
if ( ((f = k ? 0 : Choose(r, m)) < 0) ||
(_q.Init(),
!(n ? _q.LessThan(r, _p) : _q.LessThan(r, xn0, _d, _sig, j))) ||
((f = k ? Choose(r, m) : f) < 0) ||
(f == 0 && (_p.Init(), !_p.LessThan(r, xn0, _d, _sig, j))) )
break;
_p.swap(_q); // an efficient way of doing p = q
}
return (n % 2) == 0;
}
} // namespace RandomLib
#endif // RANDOMLIB_DISCRETENORMALALT_HPP

View File

@ -0,0 +1,241 @@
/**
* \file ExactExponential.hpp
* \brief Header for ExactExponential
*
* Sample exactly from an exponential distribution.
*
* Copyright (c) Charles Karney (2006-2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXACTEXPONENTIAL_HPP)
#define RANDOMLIB_EXACTEXPONENTIAL_HPP 1
#include <RandomLib/RandomNumber.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (push)
# pragma warning (disable: 4127)
#endif
namespace RandomLib {
/**
* \brief Sample exactly from an exponential distribution.
*
* Sample \e x &ge; 0 from exp(&minus;\e x). See:
* - J. von Neumann, Various Techniques used in Connection with Random
* Digits, J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38
* (1951), reprinted in Collected Works, Vol. 5, 768--770 (Pergammon,
* 1963).
* - M. Abramowitz and I. A. Stegun, Handbook of Mathematical Functions
* (National Bureau of Standards, 1964), Sec. 26.8.6.c(2).
* - G. E. Forsythe, Von Neumann's Comparison Method for Random Sampling from
* Normal and Other Distributions, Math. Comp. 26, 817--826 (1972).
* - D. E. Knuth, TAOCP, Vol 2, Sec 3.4.1.C.3.
* - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number
* Generation, in "Algorithms and Complexity" (Academic Press, 1976),
* pp. 357--428.
* - P. Flajolet and N. Saheb, The Complexity of Generating an
* Exponentially Distributed Variate, J. Algorithms 7, 463--488 (1986).
*
* The following code illustrates the basic method given by von Neumann:
* \code
// Return a random number x >= 0 distributed with probability exp(-x).
double ExpDist(RandomLib::Random& r) {
for (unsigned k = 0; ; ++k) {
double x = r.Fixed(), // executed 1/(1-exp(-1)) times on average
p = x, q;
do {
q = r.Fixed(); // executed exp(x)*cosh(x) times on average
if (!(q < p)) return k + x;
p = r.Fixed(); // executed exp(x)*sinh(x) times on average
} while (p < q);
}
}
\endcode
* This returns a result consuming exp(1)/(1 &minus; exp(-1)) = 4.30 random
* numbers on average. (Von Neumann incorrectly states that the method takes
* (1 + exp(1))/(1 &minus; exp(-1)) = 5.88 random numbers on average.)
* Because of the finite precision of Random::Fixed(), the code snippet above
* only approximates exp(&minus;\e x). Instead, it returns \e x with
* probability \e h(1 &minus; \e h)<sup><i>x</i>/<i>h</i></sup> for \e x = \e
* ih, \e h = 2<sup>&minus;53</sup>, and integer \e i &ge; 0.
*
* The above is precisely von Neumann's method. Abramowitz and Stegun
* consider a variant: sample uniform variants until the first is less than
* the sum of the rest. Forsythe converts the < ranking for the runs to &le;
* which makes the analysis of the discrete case more difficult. He also
* drops the "trick" by which the integer part of the deviate is given by the
* number of rejections when finding the fractional part.
*
* Von Neumann says of his method: "The machine has in effect computed a
* logarithm by performing only discriminations on the relative magnitude of
* numbers in (0,1). It is a sad fact of life, however, that under the
* particular conditions of the Eniac it was slightly quicker to use a
* truncated power series for log(1&minus;\e T) than to carry out all the
* discriminations."
*
* Here the code is modified to make it more efficient:
* \code
// Return a random number x >= 0 distributed with probability exp(-x).
double ExpDist(RandomLib::Random& r) {
for (unsigned k = 0; ; ++k) {
double x = r.Fixed(); // executed 1/(1-exp(-1/2)) times on average
if (x >= 0.5) continue;
double p = x, q;
do {
q = r.Fixed(); // executed exp(x)*cosh(x) times on average
if (!(q < p)) return 0.5 * k + x;
p = r.Fixed(); // executed exp(x)*sinh(x) times on average
} while (p < q);
}
}
\endcode
* In addition, the method is extended to use infinite precision uniform
* deviates implemented by RandomNumber and returning \e exact results for
* the exponential distribution. This is possible because only comparisons
* are done in the method. The template parameter \e bits specifies the
* number of bits in the base used for RandomNumber (i.e., base =
* 2<sup><i>bits</i></sup>).
*
* For example the following samples from an exponential distribution and
* prints various representations of the result.
* \code
#include <RandomLib/RandomNumber.hpp>
#include <RandomLib/ExactExponential.hpp>
RandomLib::Random r;
const int bits = 1;
RandomLib::ExactExponential<bits> edist;
for (size_t i = 0; i < 10; ++i) {
RandomLib::RandomNumber<bits> x = edist(r); // Sample
std::pair<double, double> z = x.Range();
std::cout << x << " = " // Print in binary with ellipsis
<< "(" << z.first << "," << z.second << ")"; // Print range
double v = x.Value<double>(r); // Round exactly to nearest double
std::cout << " = " << v << "\n";
}
\endcode
* Here's a possible result: \verbatim
0.0111... = (0.4375,0.5) = 0.474126
10.000... = (2,2.125) = 2.05196
1.00... = (1,1.25) = 1.05766
0.010... = (0.25,0.375) = 0.318289
10.1... = (2.5,3) = 2.8732
0.0... = (0,0.5) = 0.30753
0.101... = (0.625,0.75) = 0.697654
0.00... = (0,0.25) = 0.0969214
0.0... = (0,0.5) = 0.194053
0.11... = (0.75,1) = 0.867946 \endverbatim
* First number is in binary with ... indicating an infinite sequence of
* random bits. Second number gives the corresponding interval. Third
* number is the result of filling in the missing bits and rounding exactly
* to the nearest representable double.
*
* This class uses some mutable RandomNumber objects. So a single
* ExactExponential object cannot safely be used by multiple threads. In a
* multi-processing environment, each thread should use a thread-specific
* ExactExponential object. In addition, these should be invoked with
* thread-specific random generator objects.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 1> class ExactExponential {
public:
/**
* Return a random deviate with an exponential distribution, exp(&minus;\e
* x) for \e x &ge; 0. Requires 7.232 bits per invocation for \e bits = 1.
* The average number of bits in the fraction = 1.743. The relative
* frequency of the results for the fractional part with \e bits = 1 is
* shown by the histogram
* \image html exphist.png
* The base of each rectangle gives the range represented by the
* corresponding binary number and the area is proportional to its
* frequency. A PDF version of this figure is given
* <a href="exphist.pdf">here</a>. This allows the figure to be magnified
* to show the rectangles for all binary numbers up to 9 bits. Note that
* this histogram was generated using an earlier version of
* ExactExponential (thru version 1.3) that implements von Neumann's
* original method. The histogram generated with the current version of
* ExactExponential is the same as this figure for \e u in [0, 1/2]. The
* histogram for \e u in [1/2, 1] is obtained by shifting and scaling the
* part for \e u in [0, 1/2] to fit under the exponential curve.
*
* Another way of assessing the efficiency of the algorithm is thru the
* mean value of the balance = (number of random bits consumed) &minus;
* (number of bits in the result). If we code the result in mixed Knuth
* and Yao's unary-binary notation (integer is given in unary, followed by
* "0" as a separator, followed by the fraction in binary), then the mean
* balance is 3.906. (Flajolet and Saheb analyzed the algorithm based on
* the original von Neumann method and showed that the balance is 5.680 in
* that case.)
*
* For \e bits large, the mean number of random digits is exp(1/2)/(1
* &minus; exp(&minus;1/2)) = 4.19 (versus 4.30 digits for the original
* method).
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return the random sample.
**********************************************************************/
template<class Random> RandomNumber<bits> operator()(Random& r) const;
private:
/**
* Return true with probability exp(&minus;\e p) for \e p in (0,1/2).
**********************************************************************/
template<class Random> bool
ExpFraction(Random& r, RandomNumber<bits>& p) const;
mutable RandomNumber<bits> _x;
mutable RandomNumber<bits> _v;
mutable RandomNumber<bits> _w;
};
template<int bits> template<class Random> RandomNumber<bits>
ExactExponential<bits>::operator()(Random& r) const {
// A simple rejection method gives the 1/2 fractional part. The number of
// rejections gives the multiples of 1/2.
//
// bits: used fract un-bin balance double
// original stats: 9.31615 2.05429 3.63628 5.67987 61.59456
// new stats: 7.23226 1.74305 3.32500 3.90725 59.82198
//
// The difference between un-bin and fract is exp(1)/(exp(1)-1) = 1.58198
_x.Init();
int k = 0;
while (!ExpFraction(r, _x)) { // Executed 1/(1 - exp(-1/2)) on average
++k;
_x.Init();
}
if (k & 1) _x.RawDigit(0) += 1U << (bits - 1);
_x.AddInteger(k >> 1);
return _x;
}
template<int bits> template<class Random> bool
ExactExponential<bits>::ExpFraction(Random& r, RandomNumber<bits>& p)
const {
// The early bale out
if (p.Digit(r, 0) >> (bits - 1)) return false;
// Implement the von Neumann algorithm
_w.Init();
if (!_w.LessThan(r, p)) // if (w < p)
return true;
while (true) { // Unroll loop to avoid copying RandomNumber
_v.Init(); // v = r.Fixed();
if (!_v.LessThan(r, _w)) // if (v < w)
return false;
_w.Init(); // w = r.Fixed();
if (!_w.LessThan(r, _v)) // if (w < v)
return true;
}
}
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_EXACTEXPONENTIAL_HPP

View File

@ -0,0 +1,417 @@
/**
* \file ExactNormal.hpp
* \brief Header for ExactNormal
*
* Sample exactly from a normal distribution.
*
* Copyright (c) Charles Karney (2011-2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXACTNORMAL_HPP)
#define RANDOMLIB_EXACTNORMAL_HPP 1
#include <RandomLib/RandomNumber.hpp>
#include <algorithm> // for max/min
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (push)
# pragma warning (disable: 4127)
#endif
namespace RandomLib {
/**
* \brief Sample exactly from a normal distribution.
*
* Sample \e x from exp(&minus;<i>x</i><sup>2</sup>/2) / sqrt(2&pi;). For
* background, see:
* - J. von Neumann, Various Techniques used in Connection with Random
* Digits, J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38
* (1951), reprinted in Collected Works, Vol. 5, 768--770 (Pergammon,
* 1963).
* - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number
* Generation, in "Algorithms and Complexity" (Academic Press, 1976),
* pp. 357--428.
* - P. Flajolet and N. Saheb, The Complexity of Generating an Exponentially
* Distributed Variate, J. Algorithms 7, 463--488 (1986).
*
* The algorithm is given in
* - C. F. F. Karney, <i>Sampling exactly from the normal distribution</i>,
* http://arxiv.org/abs/1303.6257 (Mar. 2013).
* .
* In brief, the algorithm is:
* -# Select an integer \e k &ge; 0 with probability
* exp(&minus;<i>k</i>/2) (1&minus;exp(&minus;1/2)).
* -# Accept with probability
* exp(&minus; \e k (\e k &minus; 1) / 2); otherwise, reject and start
* over at step 1.
* -# Sample a random number \e x uniformly from [0,1).
* -# Accept with probability exp(&minus; \e x (\e x + 2\e k) / 2);
* otherwise, reject and start over at step 1.
* -# Set \e x = \e k + \e x.
* -# With probability 1/2, negate \e x.
* -# Return \e x.
* .
* It is easy to show that this algorithm returns samples from the normal
* distribution with zero mean and unit variance. Futhermore, all these
* steps can be carried out exactly as follows:
* - Step 1:
* - \e k = 0;
* - while (ExpProb(&minus;1/2)) increment \e k by 1.
* - Step 2:
* - \e n = \e k (\e k &minus; 1) / 2;
* - while (\e n > 0)
* { if (!ExpProb(&minus;1/2)) go to step 1; decrement \e n by 1; }
* - Step 4:
* - repeat \e k + 1 times:
* if (!ExpProb(&minus; \e x (\e x + 2\e k) / (2\e k + 2))) go to step 1.
* .
* Here, ExpProb(&minus;\e p) returns true with probability exp(&minus;\e p).
* With \e p = 1/2 (steps 1 and 2), this is implemented with von Neumann's
* rejection technique:
* - Generate a sequence of random numbers <i>U</i><sub><i>i</i></sub> and
* find the greatest \e n such that 1/2 > <i>U</i><sub>1</sub> >
* <i>U</i><sub>2</sub> > . . . > <i>U</i><sub><i>n</i></sub>. (The
* resulting value of \e n may be 0.)
* - If \e n is even, accept and return true; otherwise (\e n odd), reject
* and return false.
* .
* For \e p = \e x (\e x + 2\e k) / (2\e k + 2) (step 4), we generalize von
* Neumann's procedure as follows:
* - Generate two sequences of random numbers <i>U</i><sub><i>i</i></sub>
* and <i>V</i><sub><i>i</i></sub> and find the greatest \e n such that
* both the following conditions hold
* - \e x > <i>U</i><sub>1</sub> > <i>U</i><sub>2</sub> > . . . >
* <i>U</i><sub><i>n</i></sub>;
* - <i>V</i><sub><i>i</i></sub> &lt; (\e x + 2 \e k) / (2 \e k + 2) for
* all \e i in [1, \e n].
* .
* (The resulting value of \e n may be 0.)
* - If \e n is even, accept (return true); otherwise (\e n odd), reject
* (return false).
* .
* Here, instead of testing <i>V</i><sub><i>i</i></sub> &lt; (\e x + 2 \e k)
* / (2 \e k + 2), we carry out the following tests:
* - return true, with probability 2 \e k / (2 \e k + 2);
* - return false, with probability 1 / (2 \e k + 2);
* - otherwise (also with probability 1 / (2 \e k + 2)),
* return \e x > <i>V</i><sub><i>i</i></sub>.
* .
* The resulting method now entails evaluation of simple fractional
* probabilities (e.g., 1 / (2 \e k + 2)), or comparing random numbers (e.g.,
* <i>U</i><sub>1</sub> > <i>U</i><sub>2</sub>). These may be carried out
* exactly with a finite mean running time.
*
* With \e bits = 1, this consumes 30.1 digits on average and the result has
* 1.19 digits in the fraction. It takes about 676 ns to generate a result
* (1460 ns, including the time to round it to a double). With bits = 32, it
* takes 437 ns to generate a result (621 ns, including the time to round it
* to a double). In contrast, NormalDistribution takes about 44 ns to
* generate a double result.
*
* Another way of assessing the efficiency of the algorithm is thru the mean
* value of the balance = (number of random bits consumed) &minus; (number of
* bits in the result). If we code the result in Knuth & Yao's unary-binary
* notation, then the mean balance is 26.6.
*
* For example the following samples from a normal exponential distribution
* and prints various representations of the result.
* \code
#include <RandomLib/RandomNumber.hpp>
#include <RandomLib/ExactNormal.hpp>
RandomLib::Random r;
const int bits = 1;
RandomLib::ExactNormal<bits> ndist;
for (size_t i = 0; i < 10; ++i) {
RandomLib::RandomNumber<bits> x = ndist(r); // Sample
std::pair<double, double> z = x.Range();
std::cout << x << " = " // Print in binary with ellipsis
<< "(" << z.first << "," << z.second << ")"; // Print range
double v = x.Value<double>(r); // Round exactly to nearest double
std::cout << " = " << v << "\n";
}
\endcode
* Here's a possible result: \verbatim
-1.00... = (-1.25,-1) = -1.02142
-0.... = (-1,0) = -0.319708
0.... = (0,1) = 0.618735
-0.0... = (-0.5,0) = -0.396591
0.0... = (0,0.5) = 0.20362
0.0... = (0,0.5) = 0.375662
-1.111... = (-2,-1.875) = -1.88295
-1.10... = (-1.75,-1.5) = -1.68088
-0.... = (-1,0) = -0.577547
-0.... = (-1,0) = -0.890553
\endverbatim
* First number is in binary with ... indicating an infinite sequence of
* random bits. Second number gives the corresponding interval. Third
* number is the result of filling in the missing bits and rounding exactly
* to the nearest representable double.
*
* This class uses some mutable RandomNumber objects. So a single
* ExactNormal object cannot safely be used by multiple threads. In a
* multi-processing environment, each thread should use a thread-specific
* ExactNormal object. In addition, these should be invoked with
* thread-specific random generator objects.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 1> class ExactNormal {
public:
/**
* Return a random deviate with a normal distribution of mean 0 and
* variance 1.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return the random sample.
**********************************************************************/
template<class Random> RandomNumber<bits> operator()(Random& r) const;
private:
/**
* Return true with probability exp(&minus;1/2). For \e bits = 1, this
* consumes, on average, \e t = 2.846 random digits. We have \e t = \e a
* (1&minus;exp(&minus;1/2)) + \e b exp(&minus;1/2), where \e a is the mean
* bit count for false result = 3.786 and \e b is the mean bit count for
* true result = 2.236.
**********************************************************************/
template<class Random> bool ExpProbH(Random& r) const;
/**
* Return true with probability exp(&minus;<i>n</i>/2). For \e bits = 1,
* this consumes, on average, \e t
* (1&minus;exp(&minus;<i>n</i>/2))/(1&minus;exp(&minus;1/2)) random
* digits. A true result uses \e n \e b random digits. A false result
* uses \e a + \e b [exp(&minus;1/2)/(1&minus;exp(&minus;1/2)) &minus;
* <i>n</i> exp(&minus;<i>n</i>/2)/(1&minus;exp(&minus;<i>n</i>/2))] random
* digits.
**********************************************************************/
template<class Random> bool ExpProb(Random& r, unsigned n) const;
/**
* Return \e n with probability exp(&minus;<i>n</i>/2)
* (1&minus;exp(&minus;1/2)). For \e bits = 1, this consumes \e n \e a +
* \e b random digits if the result is \e n. Averaging over \e n this
* becomes (\e b &minus; (\e b &minus; \e a) exp(&minus;1/2))/(1 &minus;
* exp(&minus;1/2)) digits.
**********************************************************************/
template<class Random> unsigned ExpProbN(Random& r) const;
/**
* Return true with probability 1/2. This is similar to r.Boolean() but
* forces all the random results to come thru RandomNumber::RandomDigit.
**********************************************************************/
template<class Random> static bool Boolean(Random& r) {
// A more general implementation which deals with the case where the base
// might be negative is:
//
// const unsigned base = 1u << bits;
// unsigned b;
// do
// b = RandomNumber<bits>::RandomDigit(r);
// while (b == (base / 2) * 2);
// return b & 1u;
return RandomNumber<bits>::RandomDigit(r) & 1u;
}
/**
* Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2);
* return:
* - 1 (succeed unconditionally) with prob (2\e k) / (2\e k + 2),
* - 0 (succeed with probability x) with prob 1 / (2\e k + 2),
* - &minus;1 (fail unconditionally) with prob 1 / (2\e k + 2).
* .
* This simulates \code
double x = r.Fixed(); // Uniform in [0,1)
x *= (2 * k + 2);
return x < 2 * k ? 1 : (x < 2 * k + 1 ? 0 : -1);
\endcode
**********************************************************************/
template<class Random> static int Choose(Random& r, int k) {
// Limit base to 2^15 to avoid integer overflow
const int b = bits > 15 ? 15 : bits;
const unsigned mask = (1u << b) - 1;
const int m = 2 * k + 2;
int n1 = m - 2, n2 = m - 1;
// Evaluate u < n/m where u is a random real number in [0,1). Write u =
// (d + u') / 2^b where d is a random integer in [0,2^b) and u' is in
// [0,1). Then u < n/m becomes u' < n'/m where n' = 2^b * n - d * m and
// exit if n' <= 0 (false) or n' >= m (true).
while (true) {
int d = (mask & RandomNumber<bits>::RandomDigit(r)) * m;
n1 = (std::max)((n1 << b) - d, 0);
if (n1 >= m) return 1;
n2 = (std::min)((n2 << b) - d, m);
if (n2 <= 0) return -1;
if (n1 == 0 && n2 == m) return 0;
}
}
mutable RandomNumber<bits> _x;
mutable RandomNumber<bits> _p;
mutable RandomNumber<bits> _q;
};
template<int bits> template<class Random>
bool ExactNormal<bits>::ExpProbH(Random& r) const {
// Bit counts
// ExpProbH: 2.846 = 3.786 * (1-exp(-1/2)) + 2.236 * exp(-1/2)
// t = a * (1-exp(-1/2)) + b * exp(-1/2)
// t = mean bit count for result = 2.846
// a = mean bit count for false result = 3.786
// b = mean bit count for true result = 2.236
//
// for bits large
// t = exp(1/2) = 1.6487
// a = exp(1/2)/(2*(1-exp(-1/2))) = 2.0951
// b = exp(1/2)/(2*exp(-1/2)) = 1.3591
//
// Results for Prob(exp(-1)), omitting first test
// total = 5.889, false = 5.347, true = 6.826
//
// Results for Prob(exp(-1)) using ExpProbH(r) && ExpProbH(r),
// total = 4.572 = (1 - exp(-1)) * a + (1 + exp(-1/2)) * exp(-1/2) * b
// false = 4.630 = a + b * exp(-1/2)/(1 + exp(-1/2)),
// true = 4.472 = 2 * b
_p.Init();
if (_p.Digit(r, 0) >> (bits - 1)) return true;
while (true) {
_q.Init(); if (!_q.LessThan(r, _p)) return false;
_p.Init(); if (!_p.LessThan(r, _q)) return true;
}
}
template<int bits> template<class Random>
bool ExactNormal<bits>::ExpProb(Random& r, unsigned n) const {
// Bit counts
// ExpProb(n): t * (1-exp(-n/2))/(1-exp(-1/2))
// ExpProb(n) = true: n * b
// ExpProb(n) = false: a +
// b * (exp(-1/2)/(1-exp(-1/2)) - n*exp(-n/2)/(1-exp(-n/2)))
while (n--) { if (!ExpProbH(r)) return false; }
return true;
}
template<int bits> template<class Random>
unsigned ExactNormal<bits>::ExpProbN(Random& r) const {
// Bit counts
// ExpProbN() = n: n * a + b
unsigned n = 0;
while (ExpProbH(r)) ++n;
return n;
}
template<int bits> template<class Random> RandomNumber<bits>
ExactNormal<bits>::operator()(Random& r) const {
// With bits = 1,
// - mean number of bits used = 30.10434
// - mean number of bits in fraction = 1.18700
// - mean number of bits in result = 3.55257 (unary-binary)
// - mean balance = 30.10434 - 3.55257 = 26.55177
// - mean number of bits to generate a double = 83.33398
// .
// Note
// - unary-binary notation (Knuth + Yao, 1976): write x = n + y, with n =
// integer and y in [0,1). If n >=0, then write (n+1) 1's followed by a
// 0; otherwise (n < 0), write (-n) 0's followed by a 1. Write y as a
// binary fraction.
// - (bits in result) - (bits in fraction) = 2 (for encoding overhead for
// the integer part) + 0.36557, where 0.36557 = (bits used for integer
// part) = sum(k*int(sqrt(2/pi)*exp(-x^2/2), x=k..k+1), k=0..inf)
// - (bits for double) approx (bits used) - (bits in fraction) + 1 (for
// guard bit) + 53.41664 where 53.41664 = (bits in fraction of double) =
// sum((52-l)*int(sqrt(2/pi)*exp(-x^2/2), x=2^l,2^(l+1)), l=-inf..inf)
// This is approximate because it doesn't account for the minimum
// exponent, denormalized numbers, and rounding changing the exponent.
//
while (true) {
// Executed sqrt(2/pi)/(1-exp(-1/2)) = 2.027818889827955 times on
// average.
unsigned k = ExpProbN(r); // the integer part of the result.
if (ExpProb(r, (k - 1) * k)) {
// Probability that this test succeeds is
// (1 - exp(-1/2)) * sum(exp(-k/2) * exp(-(k-1)*k/2), k=0..inf))
// = (1 - exp(-1/2)) * G = 0.689875359564630
// where G = sum(exp(-k^2/2, k=0..inf) = 1.75331414402145
// For k == 0, sample from exp(-x^2/2) for x in [0,1]. This succeeds
// with probability int(exp(-x^2/2),x=0..1).
//
// For general k, substitute x' = x + k in exp(-x'^2/2), and obtain
// exp(-k^2/2) * exp(-x*(x+2*k)/2). So sample from exp(-x*(x+2*k)/2).
// This succeeds with probability int(exp(-x*(x+2*k)/2),x=0..1) =
// int(exp(-x^2/2),x=k..k+1)*exp(k^2/2) =
//
// 0.8556243918921 for k = 0
// 0.5616593588061 for k = 1
// 0.3963669350376 for k = 2
// 0.2974440159655 for k = 3
// 0.2345104783458 for k = 4
// 0.1921445042826 for k = 5
//
// Returns a result with prob sqrt(pi/2) / G = 0.714825772431666;
// otherwise another trip through the outer loop is taken.
_x.Init();
unsigned s = 1;
for (unsigned j = 0; j <= k; ++j) { // execute k + 1 times
bool first;
for (s = 1, first = true; ; s ^= 1, first = false) {
// A simpler algorithm is indicated by ALT, results in
// - mean number of bits used = 29.99968
// - mean number of bits in fraction = 1.55580
// - mean number of bits in result = 3.92137 (unary-binary)
// - mean balance = 29.99968 - 3.92137 = 26.07831
// - mean number of bits to generate a double = 82.86049
// .
// This has a smaller balance (by 0.47 bits). However the number
// of bits in the fraction is larger by 0.37
if (first) { // ALT: if (false) {
// This implements the success prob (x + 2*k) / (2*k + 2).
int y = Choose(r, k);
if (y < 0) break; // the y test fails
_q.Init();
if (y > 0) { // the y test succeeds just test q < x
if (!_q.LessThan(r, _x)) break;
} else { // the y test is ambiguous
// Test max(q, p) < x. List _q before _p since it ends up with
// slightly more digits generated (and these will be used
// subsequently). (_p's digits are immediately thrown away.)
_p.Init(); if (!_x.GreaterPair(r, _q, _p)) break;
}
} else {
// Split off the failure test for k == 0, i.e., factor the prob
// x/2 test into the product: 1/2 (here) times x (in assignment
// of y).
if (k == 0 && Boolean(r)) break;
// ALT: _q.Init(); if (!_q.LessThan(r, first ? _x : _p)) break;
_q.Init(); if (!_q.LessThan(r, _p)) break;
// succeed with prob k == 0 ? x : (x + 2*k) / (2*k + 2)
int y = k == 0 ? 0 : Choose(r, k);
if (y < 0)
break;
else if (y == 0) {
_p.Init(); if (!_p.LessThan(r, _x)) break;
}
}
_p.swap(_q); // a fast way of doing p = q
}
if (s == 0) break;
}
if (s != 0) {
_x.AddInteger(k);
if (Boolean(r)) _x.Negate(); // half of the numbers are negative
return _x;
}
}
}
}
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_EXACTNORMAL_HPP

View File

@ -0,0 +1,100 @@
/**
* \file ExactPower.hpp
* \brief Header for ExactPower
*
* Sample exactly from a power distribution.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXACTPOWER_HPP)
#define RANDOMLIB_EXACTPOWER_HPP 1
#include <RandomLib/RandomNumber.hpp>
namespace RandomLib {
/**
* \brief Sample exactly from a power distribution.
*
* Sample exactly from power distribution (<i>n</i> + 1)
* <i>x</i><sup><i>n</i></sup> for \e x in (0,1) and integer \e n &ge; 0 using
* infinite precision. The template parameter \e bits specifies the number
* of bits in the base used for RandomNumber (i.e., base =
* 2<sup><i>bits</i></sup>).
*
* This class uses some mutable RandomNumber objects. So a single ExactPower
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific ExactPower object.
* In addition, these should be invoked with thread-specific random generator
* objects.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 1> class ExactPower {
public:
/**
* Return the random deviate with a power distribution, (<i>n</i> + 1)
* <i>x</i><sup><i>n</i></sup> for \e x in (0,1) and integer \e n &ge; 0.
* Returned result is a RandomNumber with base 2<sup><i>bits</i></sup>.
* For \e bits = 1, the number of random bits in the result and consumed
* are as follows: \verbatim
n random bits
result consumed
0 0 0
1 2 4
2 2.33 6.67
3 2.67 9.24
4 2.96 11.71
5 3.20 14.11
6 3.41 16.45
7 3.59 18.75
8 3.75 21.01
9 3.89 23.25
10 4.02 25.47
\endverbatim
* The relative frequency of the results with \e bits = 1 and \e n = 2 can
* be is shown by the histogram
* \image html powerhist.png
* The base of each rectangle gives the range represented by the
* corresponding binary number and the area is proportional to its
* frequency. A PDF version of this figure
* <a href="powerhist.pdf">here</a>. This allows the figure to be
* magnified to show the rectangles for all binary numbers up to 9 bits.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] n the power.
* @return the random sample.
**********************************************************************/
template<class Random>
RandomNumber<bits> operator()(Random& r, unsigned n) const;
private:
mutable RandomNumber<bits> _x;
mutable RandomNumber<bits> _y;
};
template<int bits> template<class Random> RandomNumber<bits>
ExactPower<bits>::operator()(Random& r, unsigned n) const {
// Return max(u_0, u_1, u_2, ..., u_n). Equivalent to taking the
// (n+1)th root of u_0.
_x.Init();
for (; n--;) {
_y.Init();
// For bits = 1, we can save 1 bit on the first iteration by using a
// technique suggested by Knuth and Yao (1976). When comparing the
// digits of x and y, use 1 bit to determine if the digits are the same.
// If they are, then use another bit for the value of the digit. If they
// are not, then the next bit of the maximum must be 1 (avoiding using a
// second bit). Applying this optimization to subsequent iterations
// (when x already is filled with some bits) gets trickier.
if (_x.LessThan(r, _y))
_x.swap(_y); // x = y;
}
return _x;
}
} // namespace RandomLib
#endif // RANDOMLIB_EXACTPOWER_HPP

View File

@ -0,0 +1,69 @@
/**
* \file ExponentialDistribution.hpp
* \brief Header for ExponentialDistribution
*
* Sample from an exponential distribution.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP)
#define RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP 1
#include <cmath>
namespace RandomLib {
/**
* \brief The exponential distribution.
*
* Sample from the distribution exp(&minus;<i>x</i>/&mu;) for \e x &ge; 0.
* This uses the logarithm method, see Knuth, TAOCP, Vol 2, Sec 3.4.1.D.
* Example \code
#include <RandomLib/ExponentialDistribution.hpp>
RandomLib::Random r;
std::cout << "Seed set to " << r.SeedString() << "\n";
RandomLib::ExponentialDistribution<double> expdist;
std::cout << "Select from exponential distribution:";
for (size_t i = 0; i < 10; ++i)
std::cout << " " << expdist(r);
std::cout << "\n";
\endcode
*
* @tparam RealType the real type of the results (default double).
**********************************************************************/
template<typename RealType = double> class ExponentialDistribution {
public:
/**
* The type returned by ExponentialDistribution::operator()(Random&)
**********************************************************************/
typedef RealType result_type;
/**
* Return a sample of type RealType from the exponential distribution and
* mean &mu;. This uses Random::FloatU() which avoids taking log(0) and
* allows rare large values to be returned. If &mu; = 1, minimum returned
* value = 0 with prob 1/2<sup><i>p</i></sup>; maximum returned value =
* log(2)(\e p + \e e) with prob 1/2<sup><i>p</i> + <i>e</i></sup>. Here
* \e p is the precision of real type RealType and \e e is the exponent
* range.
*
* @tparam Random the type of RandomCanonical generator.
* @param[in,out] r the RandomCanonical generator.
* @param[in] mu the mean value of the exponential distribution (default 1).
* @return the random sample.
**********************************************************************/
template<class Random>
RealType operator()(Random& r, RealType mu = RealType(1)) const throw();
};
template<typename RealType> template<class Random> inline RealType
ExponentialDistribution<RealType>::operator()(Random& r, RealType mu) const
throw() {
return -mu * std::log(r.template FloatU<RealType>());
}
} // namespace RandomLib
#endif // RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP

View File

@ -0,0 +1,166 @@
/**
* \file ExponentialProb.hpp
* \brief Header for ExponentialProb
*
* Return true with probabililty exp(-\e p).
*
* Copyright (c) Charles Karney (2006-2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXPONENTIALPROB_HPP)
#define RANDOMLIB_EXPONENTIALPROB_HPP 1
#include <vector>
#include <limits>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (push)
# pragma warning (disable: 4127)
#endif
namespace RandomLib {
/**
* \brief The exponential probability.
*
* Return true with probability exp(&minus;\e p). Basic method taken from:\n
* J. von Neumann,\n Various Techniques used in Connection with Random
* Digits,\n J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38
* (1951),\n reprinted in Collected Works, Vol. 5, 768--770 (Pergammon,
* 1963).\n See also the references given for the ExactExponential class.
*
* Here the method is extended to be exact by generating sufficient bits in
* the random numbers in the algorithm to allow the unambiguous comparisons
* to be made.
*
* Here's one way of sampling from a normal distribution with zero mean and
* unit variance in the interval [&minus;1,1] with reasonable accuracy:
* \code
#include <RandomLib/Random.hpp>
#include <RandomLib/ExponentialProb.hpp>
double Normal(RandomLib::Random& r) {
double x;
RandomLib::ExponentialProb e;
do
x = r.FloatW();
while ( !e(r, - 0.5 * x * x) );
return x;
}
\endcode
* (Note that the ExactNormal class samples from the normal distribution
* exactly.)
*
* This class uses a mutable private vector. So a single ExponentialProb
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific ExponentialProb
* object.
**********************************************************************/
class ExponentialProb {
private:
typedef unsigned word;
public:
ExponentialProb() : _v(std::vector<word>(alloc_incr)) {}
/**
* Return true with probability exp(&minus;\e p). Returns false if \e p
* &le; 0. For in \e p (0,1], it requires about exp(\e p) random deviates.
* For \e p large, it requires about exp(1)/(1 &minus; exp(&minus;1))
* random deviates.
*
* @tparam RealType the real type of the argument.
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the probability.
* @return true with probability \e p.
**********************************************************************/
template<typename RealType, class Random>
bool operator()(Random& r, RealType p) const;
private:
/**
* Return true with probability exp(&minus;\e p) for \e p in [0,1].
**********************************************************************/
template<typename RealType, class Random>
bool ExpFraction(Random& r, RealType p) const;
/**
* Holds as much of intermediate uniform deviates as needed.
**********************************************************************/
mutable std::vector<word> _v;
/**
* Increment on size of _v.
**********************************************************************/
static const unsigned alloc_incr = 16;
};
template<typename RealType, class Random>
bool ExponentialProb::operator()(Random& r, RealType p) const {
STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
"ExponentialProb(): invalid real type RealType");
return p <= 0 || // True if p <=0
// Ensure p - 1 < p. Also deal with IsNaN(p)
( p < RealType(1)/std::numeric_limits<RealType>::epsilon() &&
// exp(a+b) = exp(a) * exp(b)
ExpFraction(r, p < RealType(1) ? p : RealType(1)) &&
( p <= RealType(1) || operator()(r, p - RealType(1)) ) );
}
template<typename RealType, class Random>
bool ExponentialProb::ExpFraction(Random& r, RealType p) const {
// Base of _v is 2^c. Adjust so that word(p) doesn't lose precision.
static const int c = // The Intel compiler needs this to be static??
std::numeric_limits<word>::digits <
std::numeric_limits<RealType>::digits ?
std::numeric_limits<word>::digits :
std::numeric_limits<RealType>::digits;
// m gives number of valid words in _v
unsigned m = 0, l = unsigned(_v.size());
if (p < RealType(1))
while (true) {
if (p <= RealType(0))
return true;
// p in (0, 1)
if (l == m)
_v.resize(l += alloc_incr);
_v[m++] = r.template Integer<word, c>();
p *= std::pow(RealType(2), c); // p in (0, 2^c)
word w = word(p); // w in [0, 2^c)
if (_v[m - 1] > w)
return true;
else if (_v[m - 1] < w)
break;
else // _v[m - 1] == w
p -= RealType(w); // p in [0, 1)
}
// Here _v < p. Now loop finding decreasing V. Exit when first increasing
// one is found.
for (unsigned s = 0; ; s ^= 1) { // Parity of loop count
for (unsigned j = 0; ; ++j) {
if (j == m) {
// Need more bits in the old V
if (l == m)
_v.resize(l += alloc_incr);
_v[m++] = r.template Integer<word, c>();
}
word w = r.template Integer<word, c>();
if (w > _v[j])
return s != 0u; // New V is bigger, so exit
else if (w < _v[j]) {
_v[j] = w; // New V is smaller, update _v
m = j + 1; // adjusting its size
break; // and generate the next V
}
// Else w == _v[j] and we need to check the next c bits
}
}
}
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_EXPONENTIALPROB_HPP

View File

@ -0,0 +1,67 @@
/**
* \file InverseEProb.hpp
* \brief Header for InverseEProb
*
* Return true with probabililty 1/\e e.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_INVERSEEPROB_HPP)
#define RANDOMLIB_INVERSEEPROB_HPP 1
#include <vector>
#include <RandomLib/Random.hpp>
namespace RandomLib {
/**
* \brief Return true with probability 1/\e e = exp(&minus;1).
*
* InverseEProb p; p(Random& r) returns true with prob 1/\e e using von
* Neumann's rejection method. It consumes 4.572 bits per call on average.
*
* This class illustrates how to return an exact result using coin tosses
* only. A more efficient way of returning an exact result would be to use
* ExponentialProb p; p(r, 1.0f);
**********************************************************************/
class InverseEProb {
private:
mutable std::vector<bool> _p;
template<class Random> bool exph(Random& r) {
// Return true with prob 1/sqrt(e).
if (r.Boolean()) return true;
_p.clear(); // vector of bits in p
_p.push_back(false);
for (bool s = false; ; s = !s) { // s is a parity
for (size_t i = 0; ; ++i) { // Compare bits of p and q
if (i == _p.size())
_p.push_back(r.Boolean()); // Generate next bit of p if necessary
if (r.Boolean()) { // Half the time the bits differ
if (_p[i]) { // p's bit is 1, so q is smaller, update p
_p[i] = false; // Last bit of q 0
if (++i < _p.size()) _p.resize(i); // p = q
break;
} else
return s; // p's bit is 0, so q is bigger, return parity
} // The other half of the time the bits match, so go to next bit
}
}
}
public:
/**
* Return true with probability 1/\e e.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return true with probability 1/\e e.
**********************************************************************/
template<class Random> bool operator()(Random& r)
{ return exph(r) && exph(r); }
};
} // namespace RandomLib
#endif // RANDOMLIB_INVERSEEPROB_HPP

View File

@ -0,0 +1,150 @@
/**
* \file InversePiProb.hpp
* \brief Header for InversePiProb
*
* Return true with probabililty 1/&pi;.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_INVERSEPIPROB_HPP)
#define RANDOMLIB_INVERSEPIPROB_HPP 1
#include <cstdlib> // for abs(int)
#include <RandomLib/Random.hpp>
namespace RandomLib {
/**
* \brief Return true with probability 1/&pi;.
*
* InversePiProb p; p(Random& r) returns true with prob 1/&pi; using the
* method of Flajolet et al. It consumes 9.6365 bits per call on average.
*
* The method is given in Section 3.3 of
* - P. Flajolet, M. Pelletier, and M. Soria,<br>
* On Buffon Machines and Numbers,<br> Proc. 22nd ACM-SIAM Symposium on
* Discrete Algorithms (SODA), Jan. 2011.<br>
* http://www.siam.org/proceedings/soda/2011/SODA11_015_flajoletp.pdf <br>
* .
* using the identity
* \f[ \frac 1\pi = \sum_{n=0}^\infty
* {{2n}\choose n}^3 \frac{6n+1}{2^{8n+2}} \f]
*
* It is based on the expression for 1/&pi; given by Eq. (28) of<br>
* - S. Ramanujan,<br>
* Modular Equations and Approximations to &pi;,<br>
* Quart. J. Pure App. Math. 45, 350--372 (1914);<br>
* In Collected Papers, edited by G. H. Hardy, P. V. Seshu Aiyar,
* B. M. Wilson (Cambridge Univ. Press, 1927; reprinted AMS, 2000).<br>
* http://books.google.com/books?id=oSioAM4wORMC&pg=PA36 <br>
* .
* \f[\frac4\pi = 1 + \frac74 \biggl(\frac 12 \biggr)^3
* + \frac{13}{4^2} \biggl(\frac {1\cdot3}{2\cdot4} \biggr)^3
* + \frac{19}{4^3} \biggl(\frac {1\cdot3\cdot5}{2\cdot4\cdot6} \biggr)^3
* + \ldots \f]
*
* The following is a description of how to carry out the algorithm "by hand"
* with a real coin, together with a worked example:
* -# Perform three coin tossing experiments in which you toss a coin until
* you get tails, e.g., <tt>HHHHT</tt>; <tt>HHHT</tt>; <tt>HHT</tt>. Let
* <i>h</i><sub>1</sub> = 4, <i>h</i><sub>2</sub> = 3,
* <i>h</i><sub>3</sub> = 2 be the numbers of heads tossed in each
* experiment.
* -# Compute <i>n</i> = &lfloor;<i>h</i><sub>1</sub>/2&rfloor; +
* &lfloor;<i>h</i><sub>2</sub>/2&rfloor; +
* mod(&lfloor;(<i>h</i><sub>3</sub> &minus; 1)/3&rfloor;, 2) = 2 + 1 + 0
* = 3. Here is a table of the 3 contributions to <i>n</i>:\verbatim
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 h
0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 floor(h1/2)
0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 floor(h2/2)
1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 mod(floor((h3-1)/3), 2)
\endverbatim
* -# Perform three additional coin tossing experiments in each of which you
* toss a coin 2<i>n</i> = 6 times, e.g., <tt>TTHHTH</tt>;
* <tt>HHTHH|H</tt>; <tt>THHHHH</tt>. Are the number of heads and tails
* equal in each experiment? <b>yes</b> and <b>no</b> and <b>no</b> &rarr;
* <b>false</b>. (Here, you can give up at the |.)
* .
* The final result in this example is <b>false</b>. The most common way a
* <b>true</b> result is obtained is with <i>n</i> = 0, in which case the
* last step vacuously returns <b>true</b>.
*
* Proof of the algorithm: Flajolet et al. rearrange Ramanujan's identity as
* \f[ \frac 1\pi = \sum_{n=0}^\infty
* \biggl[{2n\choose n} \frac1{2^{2n}} \biggr]^3
* \frac{6n+1}{2^{2n+2}}. \f]
* Noticing that
* \f[ \sum_{n=0}^\infty
* \frac{6n+1}{2^{2n+2}} = 1, \f]
* the algorithm becomes:
* -# pick <i>n</i> &ge; 0 with prob (6<i>n</i>+1) / 2<sup>2<i>n</i>+2</sup>
* (mean <i>n</i> = 11/9);
* -# return <b>true</b> with prob (binomial(2<i>n</i>, <i>n</i>) /
* 2<sup>2<i>n</i></sup>)<sup>3</sup>.
*
* Implement (1) as
* - geom4(r) + geom4(r) returns <i>n</i> with probability 9(<i>n</i> +
* 1) / 2<sup>2<i>n</i>+4</sup>;
* - geom4(r) + geom4(r) + 1 returns <i>n</i> with probability
* 36<i>n</i> / 2<sup>2<i>n</i>+4</sup>;
* - combine these with probabilities [4/9, 5/9] to yield (6<i>n</i> +
* 1) / 2<sup>2<i>n</i>+2</sup>, as required.
* .
* Implement (2) as the outcome of 3 coin tossing experiments of 2<i>n</i>
* tosses with success defined as equal numbers of heads and tails in each
* trial.
*
* This class illustrates how to return an exact result using coin tosses
* only. A more efficient implementation (which is still exact) would
* replace prob59 by r.Prob(5,9) and geom4 by LeadingZeros z; z(r)/2.
**********************************************************************/
class InversePiProb {
private:
template<class Random> bool prob59(Random& r) {
// true with prob 5/9 = 0.1 000 111 000 111 000 111 ... (binary expansion)
if (r.Boolean()) return true;
for (bool res = false; ; res = !res)
for (int i = 3; i--; ) if (r.Boolean()) return res;
}
template<class Random> int geom4(Random& r) { // Geom(1/4)
int sum = 0;
while (r.Boolean() && r.Boolean()) ++sum;
return sum;
}
template<class Random> bool binom(Random& r, int n) {
// Probability of equal heads and tails on 2*n tosses
// = binomial(2*n, n) / 2^(2*n)
int d = 0;
for (int k = n; k--; ) d += r.Boolean() ? 1 : -1;
for (int k = n; k--; ) {
d += r.Boolean() ? 1 : -1;
// This optimization saves 0.1686 bit per call to operator() on average.
if (std::abs(d) > k) return false;
}
return true;
}
public:
/**
* Return true with probability 1/&pi;.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return true with probability 1/&pi;.
**********************************************************************/
template<class Random> bool operator()(Random& r) {
// Return true with prob 1/pi.
int n = geom4(r) + geom4(r) + (prob59(r) ? 1 : 0);
for (int j = 3; j--; ) if (!binom(r, n)) return false;
return true;
}
};
} // namespace RandomLib
#endif // RANDOMLIB_INVERSEPIPROB_HPP

View File

@ -0,0 +1,84 @@
/**
* \file LeadingZeros.hpp
* \brief Header for LeadingZeros
*
* Count the leading zeros in a real number.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_LEADINGZEROS_HPP)
#define RANDOMLIB_LEADINGZEROS_HPP 1
namespace RandomLib {
/**
* \brief Count of leading zeros.
*
* Count of leading zero bits after the binary point in a real number
* uniformly distributed in (0,1). (This is equivalent to the geometric
* distribution with probability 1/2.) For example
* \code
#include <RandomLib/LeadingZeros.hpp>
RandomLib::Random r; // A RandomGenerator works here too
std::cout << "Seed set to " << r.SeedString() << "\n";
LeadingZeros zeros;
std::cout << "Count of leading zeros:";
for (size_t i = 0; i < 20; ++i)
std::cout << " " << zeros(r);
std::cout << "\n";
\endcode
**********************************************************************/
class LeadingZeros {
public:
/**
* Return the number of zero bits after the binary point in a real number
* uniformly distributed in (0,1). Thus \e k is returned with probability
* 1/2<sup><i>k</i>+1</sup>. Because MT19937 is \e not a perfect random
* number generator, this always returns a result in [0, 19937).
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return the random sample.
**********************************************************************/
template<class Random> unsigned operator()(Random& r) const throw();
};
template<class Random>
unsigned LeadingZeros::operator()(Random& r) const throw() {
// It's simpler to count the number of trailing ones in each w-bit block
// stopping when we get to a zero bit.
//
// Process a word in chunks of size m. The algorithm here can deal with
// any m assuming that z is modified accordingly. m = 4 is an approximate
// optimum.
//
// Can also adapt this routine to use RandomNumber::highest_bit_idx
// instead. However the result is considerably slower.
const int m = 4;
STATIC_ASSERT(m <= Random::width, "LeadingZeros: m too large");
// mask with m low bits set
const typename Random::result_type mask = ~(Random::max << m);
// Number of trailing 1 bits in [0, 1<<m). However, correct results are
// also obtained with any permutation of this array. This particular
// permutation is useful since the initial 1/2, 1/4, etc. can be used for
// m-1, m-2, etc. To generate the array for the next higher m, append a
// duplicate of the array and increment the last entry by one.
const unsigned z[1 << m] =
{ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, };
typename Random::result_type x = r();
for (unsigned b = m, n = 0; b < Random::width; b += m) {
n += z[x & mask]; // count trailing 1s in chunk
if (n < b) // chunk contains a 0
return n;
x >>= m; // shift out the chunk we've processed
}
// x is all ones (prob 1/2^w); process the next word.
return Random::width + operator()(r);
}
} // namespace RandomLib
#endif // RANDOMLIB_LEADINGZEROS_HPP

View File

@ -0,0 +1,92 @@
/**
* \file MPFRExponential.hpp
* \brief Header for MPFRExponential
*
* Sampling exactly from the normal distribution for MPFR.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFREXPONENTIAL_HPP)
#define RANDOMLIB_MPFREXPONENTIAL_HPP 1
#include <RandomLib/MPFRRandom.hpp>
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The exponential distribution for MPFR.
*
* This is a transcription of ExactExponential (version 1.4) for use with
* MPFR.
*
* This class uses mutable private objects. So a single MPFRExponential
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRExponential
* object.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 32> class MPFRExponential {
public:
/**
* Initialize the MPFRExponential object.
**********************************************************************/
MPFRExponential() {};
/**
* Sample from the exponential distribution with mean 1 returning a
* MPFRRandom.
*
* @param[out] t the MPFRRandom result.
* @param[in,out] r a GMP random generator.
**********************************************************************/
void operator()(MPFRRandom<bits>& t, gmp_randstate_t r) const
{ Compute(r); _x.swap(t); }
/**
* Sample from the exponential distribution with mean 1.
*
* @param[out] val the sample from the exponential distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
{ Compute(r); return _x(val, r, round); }
private:
// Disable copy constructor and assignment operator
MPFRExponential(const MPFRExponential&);
MPFRExponential& operator=(const MPFRExponential&);
int ExpFraction(gmp_randstate_t r, MPFRRandom<bits>& p) const {
// The early bale out
if (p.TestHighBit(r)) return 0;
// Implement the von Neumann algorithm
_w.Init();
if (!_w.LessThan(r, p)) return 1;
while (true) {
_v.Init(); if (!_v.LessThan(r, _w)) return 0;
_w.Init(); if (!_w.LessThan(r, _v)) return 1;
}
}
void Compute(gmp_randstate_t r) const {
_x.Init();
unsigned k = 0;
while (!ExpFraction(r, _x)) { ++k; _x.Init(); }
if (k & 1) _x.SetHighBit(r);
_x.AddInteger(k >> 1);
return;
}
mutable MPFRRandom<bits> _x;
mutable MPFRRandom<bits> _v;
mutable MPFRRandom<bits> _w;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFREXPONENTIAL_HPP

View File

@ -0,0 +1,123 @@
/**
* \file MPFRExponentialL.hpp
* \brief Header for MPFRExponentialL
*
* Sampling exactly from the exponential distribution for MPFR using the
* traditional method.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFREXPONENTIALL_HPP)
#define RANDOMLIB_MPFREXPONENTIALL_HPP 1
#include <cmath> // for log
#include <mpfr.h>
#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3)
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The exponential distribution for MPFR (the log method).
*
* This class is <b>DEPRECATED</b>. It is included for illustrative purposes
* only. The MPFRExponential class provides a much more efficient method for
* sampling from the exponential distribution.
*
* This is an adaption of ExponentialDistribution to MPFR. The changes are
* - Use MPFR's random number generator
* - Use sufficient precision internally to ensure that a correctly rounded
* result is returned.
*
* This class uses mutable private objects. So a single MPFRExponentialL
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRExponentialL
* object.
**********************************************************************/
class MPFRExponentialL {
private:
// The number of bits of randomness to add at a time.
static const long chunk_ = 32;
public:
/**
* Initialize the MPFRExponentialL object.
**********************************************************************/
MPFRExponentialL() {
mpz_init(_vi);
mpfr_init2(_eps, chunk_);
mpfr_init2(_v1, chunk_);
mpfr_init2(_v2, chunk_);
}
/**
* Destroy the MPFRExponentialL object.
**********************************************************************/
~MPFRExponentialL() {
mpfr_clear(_v2);
mpfr_clear(_v1);
mpfr_clear(_eps);
mpz_clear(_vi);
}
/**
* Sample from the exponential distribution with mean 1.
*
* @param[out] val the sample from the exponential distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const {
mpfr_prec_t prec0 = mpfr_get_prec (val);
mpfr_prec_t prec = prec0 + 10; // A rough optimum
mpz_urandomb(_vi, r, prec);
mpfr_set_ui_2exp(_eps, 1u, -prec, MPFR_RNDN);
mpfr_set_prec(_v1, prec);
mpfr_set_z_2exp(_v1, _vi, -prec, MPFR_RNDN);
mpfr_set_prec(_v2, prec);
mpfr_add(_v2, _v1, _eps, MPFR_RNDN);
while (true) {
int f2 = mpfr_log(val, _v2, round); // val = log(upper bound)
mpfr_set_prec(_v2, prec0);
int f1 = mpfr_log(_v2, _v1, round); // v2 = log(lower bound)
if (f1 == f2 && mpfr_equal_p(val, _v2)) {
mpfr_neg(val, val, MPFR_RNDN);
return -f1;
}
prec = Refine(r, prec);
}
}
private:
// disable copy constructor and assignment operator
MPFRExponentialL(const MPFRExponentialL&);
MPFRExponentialL& operator=(const MPFRExponentialL&);
// Refine the random interval
mpfr_prec_t Refine(gmp_randstate_t r, mpfr_prec_t prec)
const {
prec += chunk_;
mpfr_div_2ui(_eps, _eps, chunk_, MPFR_RNDN);
mpz_urandomb(_vi, r, chunk_);
mpfr_set_prec(_v2, prec);
mpfr_set_z_2exp(_v2, _vi, -prec, MPFR_RNDN);
mpfr_add(_v2, _v1, _v2, MPFR_RNDN);
mpfr_swap(_v1, _v2); // v1 = v2;
mpfr_set_prec(_v2, prec);
mpfr_add(_v2, _v1, _eps, MPFR_RNDN);
return prec;
}
mutable mpz_t _vi;
mutable mpfr_t _eps;
mutable mpfr_t _v1;
mutable mpfr_t _v2;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFREXPONENTIALL_HPP

View File

@ -0,0 +1,144 @@
/**
* \file MPFRNormal.hpp
* \brief Header for MPFRNormal
*
* Sampling exactly from the normal distribution for MPFR.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRNORMAL_HPP)
#define RANDOMLIB_MPFRNORMAL_HPP 1
#include <algorithm> // for max/min
#include <RandomLib/MPFRRandom.hpp>
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The normal distribution for MPFR.
*
* This is a transcription of ExactNormal (version 1.3) for use with MPFR.
*
* This class uses mutable private objects. So a single MPFRNormal object
* cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRNormal object.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 32> class MPFRNormal {
public:
/**
* Initialize the MPFRNormal object.
**********************************************************************/
MPFRNormal() { mpz_init(_tt); }
/**
* Destroy the MPFRNormal object.
**********************************************************************/
~MPFRNormal() { mpz_clear(_tt); }
/**
* Sample from the normal distribution with mean 0 and variance 1 returning
* a MPFRRandom.
*
* @param[out] t the MPFRRandom result.
* @param[in,out] r a GMP random generator.
**********************************************************************/
void operator()(MPFRRandom<bits>& t,gmp_randstate_t r) const
{ Compute(r); return _x.swap(t); }
/**
* Sample from the normal distribution with mean 0 and variance 1.
*
* @param[out] val the sample from the normal distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn;1 if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
{ Compute(r); return _x(val, r, round); }
private:
// Disable copy constructor and assignment operator
MPFRNormal(const MPFRNormal&);
MPFRNormal& operator=(const MPFRNormal&);
// True with prob exp(-1/2)
int ExpProbH(gmp_randstate_t r) const {
_p.Init(); if (_p.TestHighBit(r)) return 1;
// von Neumann rejection
while (true) {
_q.Init(); if (!_q.LessThan(r, _p)) return 0;
_p.Init(); if (!_p.LessThan(r, _q)) return 1;
}
}
// True with prob exp(-n/2)
int ExpProb(gmp_randstate_t r, unsigned n) const {
while (n--) { if (!ExpProbH(r)) return 0; }
return 1;
}
// n with prob (1-exp(-1/2)) * exp(-n/2)
unsigned ExpProbN(gmp_randstate_t r) const {
unsigned n = 0;
while (ExpProbH(r)) ++n;
return n;
}
// Return:
// 1 with prob 2k/(2k + 2)
// 0 with prob 1/(2k + 2)
// -1 with prob 1/(2k + 2)
int Choose(gmp_randstate_t r, int k) const {
const int b = 15; // To avoid integer overflow on multiplication
const int m = 2 * k + 2;
int n1 = m - 2, n2 = m - 1;
while (true) {
mpz_urandomb(_tt, r, b);
int d = int( mpz_get_ui(_tt) ) * m;
n1 = (std::max)((n1 << b) - d, 0);
if (n1 >= m) return 1;
n2 = (std::min)((n2 << b) - d, m);
if (n2 <= 0) return -1;
if (n1 == 0 && n2 == m) return 0;
}
}
void Compute(gmp_randstate_t r) const {
while (true) {
unsigned k = ExpProbN(r); // the integer part of the result.
if (ExpProb(r, (k - 1) * k)) {
_x.Init();
unsigned s = 1;
for (unsigned j = 0; j <= k; ++j) { // execute k + 1 times
bool first;
for (s = 1, first = true; ; s ^= 1, first = false) {
if (k == 0 && _x.Boolean(r)) break;
_q.Init(); if (!_q.LessThan(r, first ? _x : _p)) break;
int y = k == 0 ? 0 : Choose(r, k);
if (y < 0)
break;
else if (y == 0) {
_p.Init(); if (!_p.LessThan(r, _x)) break;
}
_p.swap(_q); // a fast way of doing p = q
}
if (s == 0) break;
}
if (s != 0) {
_x.AddInteger(k);
if (_x.Boolean(r)) _x.Negate();
return;
}
}
}
}
mutable mpz_t _tt; // A temporary
mutable MPFRRandom<bits> _x;
mutable MPFRRandom<bits> _p;
mutable MPFRRandom<bits> _q;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRNORMAL_HPP

View File

@ -0,0 +1,138 @@
/**
* \file MPFRNormalK.hpp
* \brief Header for MPFRNormalK
*
* Sampling exactly from the normal distribution for MPFR.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRNORMALK_HPP)
#define RANDOMLIB_MPFRNORMALK_HPP 1
#include <algorithm> // for max
#include <RandomLib/MPFRRandom.hpp>
#include <RandomLib/MPFRExponential.hpp>
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The normal distribution for MPFR (Kahn algorithm).
*
* This class is <b>DEPRECATED</b>. It is included for illustrative purposes
* only. The MPFRNormal class provides a somewhat more efficient method for
* sampling from the normal distribution.
*
* Refs:
* - H. Kahn, Rand Report RM-1237-AEC, p. 41 (1954).
* - M. Abramowitz and I. A. Stegun, p. 953, Sec. 26.8.6.a(4) (1964).
* .
* N.B. Damien Stehle' drew my attention to this algorithm as a useful way to
* compute normal deviates exactly.
*
* This class uses mutable private objects. So a single MPFRNormalK object
* cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRNormalK object.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 32> class MPFRNormalK {
public:
/**
* Initialize the MPFRNormalK object.
**********************************************************************/
MPFRNormalK()
{ mpfr_init2(_xf, MPFR_PREC_MIN); mpfr_init2(_zf, MPFR_PREC_MIN); }
/**
* Destroy the MPFRNormalK object.
**********************************************************************/
~MPFRNormalK()
{ mpfr_clear(_zf); mpfr_clear(_xf); }
/**
* Sample from the normal distribution with mean 0 and variance 1 returning
* a MPFRRandom.
*
* @param[out] t the MPFRRandom result.
* @param[in,out] r a GMP random generator.
**********************************************************************/
void operator()(MPFRRandom<bits>& t, gmp_randstate_t r) const
{ Compute(r); _x.swap(t); }
/**
* Sample from the normal distribution with mean 0 and variance 1.
*
* @param[out] val the sample from the normal distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn;1 if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
{ Compute(r); return _x(val, r, round); }
private:
// disable copy constructor and assignment operator
MPFRNormalK(const MPFRNormalK&);
MPFRNormalK& operator=(const MPFRNormalK&);
void Compute(gmp_randstate_t r) const {
// The algorithm is sample x and z from the exponential distribution; if
// (x-1)^2 < 2*z, return (random sign)*x; otherwise repeat. Probability
// of acceptance is sqrt(pi/2) * exp(-1/2) = 0.7602.
while (true) {
_edist(_x, r);
_edist(_z, r);
for (mp_size_t k = 1; ; ++k) {
_x.ExpandTo(r, k - 1);
_z.ExpandTo(r, k - 1);
mpfr_prec_t prec = (std::max)(mpfr_prec_t(MPFR_PREC_MIN), k * bits);
mpfr_set_prec(_xf, prec);
mpfr_set_prec(_zf, prec);
// Try for acceptance first; so compute upper limit on (y-1)^2 and
// lower limit on 2*z.
if (_x.UInteger() == 0) {
_x(_xf, MPFR_RNDD);
mpfr_ui_sub(_xf, 1u, _xf, MPFR_RNDU);
} else {
_x(_xf, MPFR_RNDU);
mpfr_sub_ui(_xf, _xf, 1u, MPFR_RNDU);
}
mpfr_sqr(_xf, _xf, MPFR_RNDU);
_z(_zf, MPFR_RNDD);
mpfr_mul_2ui(_zf, _zf, 1u, MPFR_RNDD);
if (mpfr_cmp(_xf, _zf) < 0) { // (y-1)^2 < 2*z, so accept
if (_x.Boolean(r)) _x.Negate(); // include a random sign
return;
}
// Try for rejection; so compute lower limit on (y-1)^2 and upper
// limit on 2*z.
if (_x.UInteger() == 0) {
_x(_xf, MPFR_RNDU);
mpfr_ui_sub(_xf, 1u, _xf, MPFR_RNDD);
} else {
_x(_xf, MPFR_RNDD);
mpfr_sub_ui(_xf, _xf, 1u, MPFR_RNDD);
}
mpfr_sqr(_xf, _xf, MPFR_RNDD);
_z(_zf, MPFR_RNDU);
mpfr_mul_2ui(_zf, _zf, 1u, MPFR_RNDU);
if (mpfr_cmp(_xf, _zf) > 0) // (y-1)^2 > 2*z, so reject
break;
// Otherwise repeat with more precision
}
// Reject and start over with a new y and z
}
}
mutable MPFRRandom<bits> _x;
mutable MPFRRandom<bits> _z;
mutable mpfr_t _xf;
mutable mpfr_t _zf;
const MPFRExponential<bits> _edist;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRNORMALK_HPP

View File

@ -0,0 +1,255 @@
/**
* \file MPFRNormalR.hpp
* \brief Header for MPFRNormalR
*
* Sampling exactly from the normal distribution for MPFR using the ratio
* method.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRNORMALR_HPP)
#define RANDOMLIB_MPFRNORMALR_HPP 1
#include <algorithm> // for max/min
#include <cmath> // for pow
#include <mpfr.h>
#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3)
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The normal distribution for MPFR (ratio method).
*
* This class is <b>DEPRECATED</b>. It is included for illustrative purposes
* only. The MPFRNormal class provides a much more efficient method for
* sampling from the normal distribution.
*
* This is an adaption of NormalDistribution to MPFR. The changes are
* - Use MPFR's random number generator
* - Use sufficient precision internally to ensure that a correctly rounded
* result is returned.
*
* This class uses a mutable private object. So a single MPFRNormalR
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRNormalR
* object.
**********************************************************************/
class MPFRNormalR {
private:
// The number of bits of randomness to add at a time. Require that Leva's
// bounds "work" at a precision of 2^-chunk and that an unsigned long can
// hold this many bits.
static const long chunk_ = 32;
static const unsigned long m = 3684067834; // ceil(2^chunk*sqrt(2/e))
public:
/**
* Initialize the MPFRNormalR object.
**********************************************************************/
MPFRNormalR() {
mpz_init(_ui);
mpz_init(_vi);
mpfr_init2(_eps, chunk_);
mpfr_init2(_u, chunk_);
mpfr_init2(_v, chunk_);
mpfr_init2(_up, chunk_);
mpfr_init2(_vp, chunk_);
mpfr_init2(_vx, chunk_);
mpfr_init2(_x1, chunk_);
mpfr_init2(_x2, chunk_);
}
/**
* Destroy the MPFRNormalR object.
**********************************************************************/
~MPFRNormalR() {
mpfr_clear(_x2);
mpfr_clear(_x1);
mpfr_clear(_vx);
mpfr_clear(_vp);
mpfr_clear(_up);
mpfr_clear(_v);
mpfr_clear(_u);
mpfr_clear(_eps);
mpz_clear(_vi);
mpz_clear(_ui);
}
/**
* Sample from the normal distribution with mean 0 and variance 1.
*
* @param[out] val the sample from the normal distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn;1 if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const {
const double
s = 0.449871, // Constants from Leva
t = -0.386595,
a = 0.19600 ,
b = 0.25472 ,
r1 = 0.27597 ,
r2 = 0.27846 ,
u1 = 0.606530, // sqrt(1/e) rounded down and up
u2 = 0.606531,
scale = std::pow(2.0, -chunk_); // for turning randoms into doubles
while (true) {
mpz_urandomb(_vi, r, chunk_);
if (mpz_cmp_ui(_vi, m) >= 0) continue; // Very early reject
double vf = (mpz_get_ui(_vi) + 0.5) * scale;
mpz_urandomb(_ui, r, chunk_);
double uf = (mpz_get_ui(_ui) + 0.5) * scale;
double
x = uf - s,
y = vf - t,
Q = x*x + y * (a*y - b*x);
if (Q >= r2) continue; // Early reject
mpfr_set_ui_2exp(_eps, 1u, -chunk_, MPFR_RNDN);
mpfr_prec_t prec = chunk_;
mpfr_set_prec(_u, prec);
mpfr_set_prec(_v, prec);
// (u,v) = sw corner of range
mpfr_set_z_2exp(_u, _ui, -prec, MPFR_RNDN);
mpfr_set_z_2exp(_v, _vi, -prec, MPFR_RNDN);
mpfr_set_prec(_up, prec);
mpfr_set_prec(_vp, prec);
// (up,vp) = ne corner of range
mpfr_add(_up, _u, _eps, MPFR_RNDN);
mpfr_add(_vp, _v, _eps, MPFR_RNDN);
// Estimate how many extra bits will be needed to achieve the desired
// precision.
mpfr_prec_t prec_guard = 3 + chunk_ -
(std::max)(mpz_sizeinbase(_ui, 2), mpz_sizeinbase(_vi, 2));
if (Q > r1) {
int reject;
while (true) {
// Rejection curve v^2 + 4 * u^2 * log(u) < 0 has a peak at u =
// exp(-1/2) = 0.60653066. So treat uf in (0.606530, 0.606531) =
// (u1, u2) specially
// Try for rejection first
if (uf <= u1)
reject = Reject(_u, _vp, prec, MPFR_RNDU);
else if (uf >= u2)
reject = Reject(_up, _vp, prec, MPFR_RNDU);
else { // u in (u1, u2)
mpfr_set_prec(_vx, prec);
mpfr_add(_vx, _vp, _eps, MPFR_RNDN);
reject = Reject(_u, _vx, prec, MPFR_RNDU); // Could use _up too
}
if (reject < 0) break; // tried to reject but failed, so accept
// Try for acceptance
if (uf <= u1)
reject = Reject(_up, _v, prec, MPFR_RNDD);
else if (uf >= u2)
reject = Reject(_u, _v, prec, MPFR_RNDD);
else { // u in (u2, u2)
mpfr_sub(_vx, _v, _eps, MPFR_RNDN);
reject = Reject(_u, _vx, prec, MPFR_RNDD); // Could use _up too
}
if (reject > 0) break; // tried to accept but failed, so reject
prec = Refine(r, prec); // still can't decide, to refine
}
if (reject > 0) continue; // reject, back to outer loop
}
// Now evaluate v/u to the necessary precision
mpfr_prec_t prec0 = mpfr_get_prec (val);
// while (prec < prec0 + prec_guard) prec = Refine(r, prec);
if (prec < prec0 + prec_guard)
prec = Refine(r, prec,
(prec0 + prec_guard - prec + chunk_ - 1) / chunk_);
mpfr_set_prec(_x1, prec0);
mpfr_set_prec(_x2, prec0);
int flag;
while (true) {
int
f1 = mpfr_div(_x1, _v, _up, round), // min slope
f2 = mpfr_div(_x2, _vp, _u, round); // max slope
if (f1 == f2 && mpfr_equal_p(_x1, _x2)) {
flag = f1;
break;
}
prec = Refine(r, prec);
}
mpz_urandomb(_ui, r, 1);
if (mpz_tstbit(_ui, 0)) {
flag = -flag;
mpfr_neg(val, _x1, MPFR_RNDN);
} else
mpfr_set(val, _x1, MPFR_RNDN);
// std::cerr << uf << " " << vf << " " << Q << "\n";
return flag;
}
}
private:
// disable copy constructor and assignment operator
MPFRNormalR(const MPFRNormalR&);
MPFRNormalR& operator=(const MPFRNormalR&);
// Refine the random square
mpfr_prec_t Refine(gmp_randstate_t r, mpfr_prec_t prec, long num = 1)
const {
if (num <= 0) return prec;
// Use _vx as scratch
prec += num * chunk_;
mpfr_div_2ui(_eps, _eps, num * chunk_, MPFR_RNDN);
mpz_urandomb(_ui, r, num * chunk_);
mpfr_set_prec(_up, prec);
mpfr_set_z_2exp(_up, _ui, -prec, MPFR_RNDN);
mpfr_set_prec(_vx, prec);
mpfr_add(_vx, _u, _up, MPFR_RNDN);
mpfr_swap(_u, _vx); // u = vx
mpfr_add(_up, _u, _eps, MPFR_RNDN);
mpz_urandomb(_vi, r, num * chunk_);
mpfr_set_prec(_vp, prec);
mpfr_set_z_2exp(_vp, _vi, -prec, MPFR_RNDN);
mpfr_set_prec(_vx, prec);
mpfr_add(_vx, _v, _vp, MPFR_RNDN);
mpfr_swap(_v, _vx); // v = vx
mpfr_add(_vp, _v, _eps, MPFR_RNDN);
return prec;
}
// Evaluate the sign of the rejection condition v^2 + 4*u^2*log(u)
int Reject(mpfr_t u, mpfr_t v, mpfr_prec_t prec, mpfr_rnd_t round) const {
// Use x1, x2 as scratch
mpfr_set_prec(_x1, prec);
mpfr_log(_x1, u, round);
mpfr_mul(_x1, _x1, u, round); // Important to do the multiplications in
mpfr_mul(_x1, _x1, u, round); // this order so that rounding works right.
mpfr_mul_2ui(_x1, _x1, 2u, round); // 4*u^2*log(u)
mpfr_set_prec(_x2, prec);
mpfr_mul(_x2, v, v, round); // v^2
mpfr_add(_x1, _x1, _x2, round); // v^2 + 4*u^2*log(u)
return mpfr_sgn(_x1);
}
mutable mpz_t _ui;
mutable mpz_t _vi;
mutable mpfr_t _eps;
mutable mpfr_t _u;
mutable mpfr_t _v;
mutable mpfr_t _up;
mutable mpfr_t _vp;
mutable mpfr_t _vx;
mutable mpfr_t _x1;
mutable mpfr_t _x2;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRNORMALR_HPP

View File

@ -0,0 +1,383 @@
/**
* \file MPFRRandom.hpp
* \brief Header for MPFRRandom
*
* Utility class for MPFRUniform, MPFRExponential, and MPFRNormal.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRRANDOM_HPP)
#define RANDOMLIB_MPFRRANDOM_HPP 1
#include <algorithm> // for swap
#include <mpfr.h>
#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3)
#if HAVE_MPFR || defined(DOXYGEN)
/**
* A compile-time assert. Use C++11 static_assert, if available.
**********************************************************************/
#if !defined(STATIC_ASSERT)
# if defined(__GXX_EXPERIMENTAL_CXX0X__)
# define STATIC_ASSERT static_assert
# elif defined(_MSC_VER) && _MSC_VER >= 1600
# define STATIC_ASSERT static_assert
# else
# define STATIC_ASSERT(cond,reason) \
{ enum{ STATIC_ASSERT_ENUM = 1/int(cond) }; }
# endif
#endif
namespace RandomLib {
/**
* \brief Handling random numbers in MPFR.
*
* This class provides roughly the same capabilities as RandomNumber. The
* fraction is represented by a mpz integer \e f and an exponent \e e. We
* have \e e &ge; 0 and 0 &le; \e f < <i>b</i><sup><i>e</i></sup>, and \e b =
* 2<sup><i>bits</i></sup>. This represents the number \e x = \e f
* <i>b</i><sup>&minus;<i>e</i></sup>, with x in [0, 1).
*
* @tparam bits the number of bits in each digit.
*
* \e bits must divide GMP_LIMB_BITS. The default value \e bits = 32 yields
* portable results on all MPFR platforms.
**********************************************************************/
template<int bits = 32> class MPFRRandom {
private:
static const int limb_ = GMP_LIMB_BITS; // How many bits in a limb
static const int loglimb_ = (limb_ == 32 ? 5 :
(limb_ == 64 ? 6 :
(limb_ == 128 ? 7 : -1)));
static const int logbits_ = (bits == 1 ? 0 :
(bits == 2 ? 1 :
(bits == 4 ? 2 :
(bits == 8 ? 3 :
(bits == 16 ? 4 :
(bits == 32 ? 5 :
(bits == 64 ? 6 :
(bits == 128 ? 7 : -1))))))));
static const mp_limb_t mask_ = (bits == limb_ ? ~0UL : // Digit mask
~(~0UL << (bits < limb_ ? bits : 0)));
static const int logw_ = loglimb_ - logbits_; // 2^logw digits per limb
static const unsigned wmask_ = ~(~0U << logw_);
mutable mpz_t _tt; // A temporary
mpz_t _f; // The fraction
mp_size_t _e; // Count of digits
unsigned long _n; // Integer part
int _s; // Sign
void AddDigits(gmp_randstate_t r, long num = 1) { // Add num more digits
if (num <= 0) return;
mpz_mul_2exp(_f, _f, num << logbits_);
mpz_urandomb(_tt, r, num << logbits_);
mpz_add(_f, _f, _tt);
_e += num;
}
// return k'th digit counting k = 0 as most significant
mp_limb_t Digit(gmp_randstate_t r, mp_size_t k) {
ExpandTo(r, k); // Now e > k
k = _e - 1 - k; // Reverse k so k = 0 is least significant
// (k >> logw) is the limb index
// (k & wmask) is the digit position within the limb
return mask_ &
(mpz_getlimbn(_f, k >> logw_) >> ((k & wmask_) << logbits_));
}
// Return index [0..32] of highest bit set. Return 0 if x = 0, 32 is if x
// = ~0. (From Algorithms for programmers by Joerg Arndt.)
static int highest_bit_idx(unsigned long x) throw() {
if (x == 0) return 0;
int r = 1;
// STILL TO DO: handle 64-bit unsigned longs.
if (x & 0xffff0000UL) { x >>= 16; r += 16; }
if (x & 0x0000ff00UL) { x >>= 8; r += 8; }
if (x & 0x000000f0UL) { x >>= 4; r += 4; }
if (x & 0x0000000cUL) { x >>= 2; r += 2; }
if (x & 0x00000002UL) { r += 1; }
return r;
}
public:
/**
* Initialize the MPFRRandom object.
**********************************************************************/
MPFRRandom() : _e(0u), _n(0u), _s(1) {
STATIC_ASSERT(logbits_ >= 0 && loglimb_ >= 0 && logbits_ <= loglimb_,
"MPRFRandom: unsupported value for bits");
mpz_init(_f); mpz_init(_tt);
}
/**
* Initialize the MPFRRandom object from another one.
*
* @param[in] t the MPFRRandom to copy.
**********************************************************************/
MPFRRandom(const MPFRRandom& t) : _e(t._e), _n(t._n), _s(t._s)
{ mpz_init(_f); mpz_set(_f, t._f); mpz_init(_tt); }
/**
* Destroy the MPFRRandom object.
**********************************************************************/
~MPFRRandom() { mpz_clear(_f); mpz_clear(_tt); }
/**
* Assignment operator. (But swapping is typically faster.)
*
* @param[in] t the MPFRRandom to copy.
**********************************************************************/
MPFRRandom& operator=(const MPFRRandom& t) {
_e = t._e;
_n = t._n;
_s = t._s;
mpz_set(_f, t._f); // Don't copy _tt
return *this;
}
/**
* Swap with another MPFRRandom. This is a fast way of doing an
* assignment.
*
* @param[in,out] t the MPFRRandom to swap with.
**********************************************************************/
void swap(MPFRRandom& t) throw() {
if (this != &t) {
std::swap(_e, t._e);
std::swap(_n, t._n);
std::swap(_s, t._s);
mpz_swap(_f, t._f); // Don't swap _tt
}
}
/**
* Reinitialize the MPFRRandom object, setting its value to [0,1].
**********************************************************************/
void Init() { mpz_set_ui(_f, 0u); _e = 0; _n = 0; _s = 1; }
/**
* @return the sign of the MPFRRandom (&plusmn; 1).
**********************************************************************/
int Sign() const throw() { return _s; }
/**
* Change the sign of the MPFRRandom.
**********************************************************************/
void Negate() throw() { _s *= -1; }
/**
* @return the floor of the MPFRRandom
**********************************************************************/
long Floor() const throw() { return _s > 0 ? long(_n) : -1 - long(_n); }
/**
* @return the ceiling of the MPFRRandom
**********************************************************************/
long Ceiling() const throw() { return _s > 0 ? 1 + long(_n) : -long(_n); }
/**
* @return the unsigned integer component of the MPFRRandom.
**********************************************************************/
unsigned long UInteger() const throw() { return _n; }
/**
* @return the number of digits in fraction
**********************************************************************/
unsigned long Size() const throw() { return unsigned(_e); }
/**
* Add integer \e k to the MPRFRandom.
*
* @param[in] k the integer to add.
**********************************************************************/
void AddInteger(long k) {
k += Floor(); // The new floor
int ns = k < 0 ? -1 : 1; // The new sign
if (ns != _s) { // If sign changes, set f = 1 - f
mpz_set_ui(_tt, 1u);
mpz_mul_2exp(_tt, _tt, _e << logbits_);
mpz_sub_ui(_tt, _tt, 1u);
mpz_sub(_f, _tt, _f);
_s = ns;
}
_n = ns > 0 ? k : -(k + 1);
}
/**
* Compare with another MPFRRandom, *this < \e t.
*
* @param[in,out] r a random generator.
* @param[in,out] t a MPFRRandom to compare.
* @return true if *this < \e t.
**********************************************************************/
int LessThan(gmp_randstate_t r, MPFRRandom& t) {
if (this == &t) return false; // same object
if (_s != t._s) return _s < t._s;
if (_n != t._n) return (_s < 0) ^ (_n < t._n);
for (mp_size_t k = 0; ; ++k) {
mp_limb_t x = Digit(r, k);
mp_limb_t y = t.Digit(r, k);
if (x != y) return (_s < 0) ^ (x < y);
}
}
/**
* Set high bit of fraction to 1.
*
* @param[in,out] r a random generator.
**********************************************************************/
void SetHighBit(gmp_randstate_t r) { // Set the msb to 1
ExpandTo(r, 0); // Generate msb if necessary
mpz_setbit(_f, (_e << logbits_) - 1);
}
/**
* Test high bit of fraction.
*
* @param[in,out] r a random generator.
**********************************************************************/
int TestHighBit(gmp_randstate_t r) { // test the msb of f
ExpandTo(r, 0); // Generate msb if necessary
return mpz_tstbit(_f, (_e << logbits_) - 1);
}
/**
* Return the position of the most significant bit in the MPFRRandom.
*
* @param[in,out] r a random generator.
*
* The bit position is numbered such the 1/2 bit is 0, the 1/4 bit is -1,
* etc.
**********************************************************************/
mp_size_t LeadingBit(gmp_randstate_t r) {
if (_n) return highest_bit_idx(_n);
while (true) {
int sgn = mpz_sgn(_f);
if (sgn != 0)
return mp_size_t(mpz_sizeinbase(_f, 2)) - mp_size_t(_e << logbits_);
AddDigits(r);
}
}
/**
* Ensure that the k'th digit of the fraction is computed.
*
* @param[in,out] r a random generator.
* @param[in] k the digit number (0 is the most significant, 1 is the next
* most significant, etc.
**********************************************************************/
void ExpandTo(gmp_randstate_t r, mp_size_t k)
{ if (_e <= k) AddDigits(r, k - _e + 1); }
/**
* Convert to a MPFR number \e without adding more bits.
*
* @param[out] val the value of s * (n + *this).
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
*
* If round is MPFR_RNDN, then the rounded midpoint of the interval
* represented by the MPFRRandom is returned. Otherwise it is the rounded
* lower or upper bound of the interval (whichever is appropriate).
**********************************************************************/
int operator()(mpfr_t val, mpfr_rnd_t round)
{ return operator()(val, NULL, round); }
/**
* Convert to a MPFR number.
*
* @param[out] val the value of s * (n + *this).
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
*
* If \e r is NULL, then no additional random bits are generated and the
* lower bound, midpoint, or upper bound of the MPFRRandom interval is
* returned, depending on the value of \e round.
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) {
// The value is constructed as a positive quantity, so adjust rounding
// mode to account for this.
switch (round) {
case MPFR_RNDD:
case MPFR_RNDU:
case MPFR_RNDN:
break;
case MPFR_RNDZ:
round = _s < 0 ? MPFR_RNDU : MPFR_RNDD;
break;
case MPFR_RNDA:
round = _s < 0 ? MPFR_RNDD : MPFR_RNDU;
break;
default:
round = MPFR_RNDN; // New rounding modes are variants of N
break;
} // Now round is one of MPFR_RND{D,N,U}
mp_size_t excess;
mpfr_exp_t expt;
if (r == NULL) {
// If r is NULL then all the bits currently generated are considered
// significant. Thus no excess bits need to be squeezed out.
excess = 0;
// And the exponent shift in mpfr_set_z_2exp is just...
expt = -(_e << logbits_);
// However, if rounding to nearest, we need to make room for the
// midpoint bit.
if (round == MPFR_RNDN) {
excess = -1;
--expt;
}
} else { // r is non-NULL
// Generate enough digits, i.e., enough to generate prec significant
// figures for RNDD and RNDU; for RNDN we need to generate an
// additional guard bit.
mp_size_t lead = LeadingBit(r);
mpfr_prec_t prec = mpfr_get_prec (val);
mp_size_t trail = lead - prec; // position one past trailing bit
mp_size_t guard = trail + (round == MPFR_RNDN ? 0 : 1); // guard bit pos
// Generate the bits needed.
if (guard <= 0) ExpandTo(r, (-guard) >> logbits_);
// Unless bits = 1, the generation process will typically have
// generated too many bits. We figure out how many, but leaving room
// for one additional "inexact" bit. The inexact bit is set to 1 in
// order to force MPFR to treat the result as inexact, to break RNDN
// ties, and to get the ternary value set correctly.
//
// expt is the exponent used when forming the number using
// mpfr_set_z_2exp. Without the inexact bit, it's (guard - 1).
// Subtract 1 to account for the inexact bit.
expt = guard - 2;
// The number of excess bits is now the difference between the number
// of bits in the fraction (e << logbits) and -expt. Note that this
// may be -1 (meaning we'll need to shift the number left to
// accommodate the inexact bit).
excess = (_e << logbits_) + expt;
}
mpz_set_ui(_tt, _n); // The integer part
mpz_mul_2exp(_tt, _tt, _e << logbits_); // Shift to allow for fraction
mpz_add(_tt, _tt, _f); // Add fraction
if (excess > 0)
mpz_tdiv_q_2exp(_tt, _tt, excess);
else if (excess < 0)
mpz_mul_2exp(_tt, _tt, -excess);
if (r || round == MPFR_RNDN)
// Set the inexact bit (or compute the midpoint if r is NULL).
mpz_setbit(_tt, 0);
else if (round == MPFR_RNDU)
// If r is NULL, compute the upper bound.
mpz_add_ui(_tt, _tt, 1u);
// Convert to a mpfr number. If r is specified, then there are
// sufficient bits in tt that the result is inexact and that (in the case
// of RNDN) there are no ties.
int flag = mpfr_set_z_2exp(val, _tt, expt, round);
if (_s < 0) {
mpfr_neg (val, val, MPFR_RNDN);
flag = -flag;
}
return flag;
}
/**
* A coin toss. (This should really be a static function. But it uses the
* MPFRRandom temporary variable.)
*
* @param[in,out] r a GMP random generator.
* @return true or false.
**********************************************************************/
int Boolean(gmp_randstate_t r) const {
mpz_urandomb(_tt, r, 1);
return mpz_tstbit(_tt, 0);
}
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRRANDOM_HPP

View File

@ -0,0 +1,72 @@
/**
* \file MPFRUniform.hpp
* \brief Header for MPFRUniform
*
* Sampling exactly from a uniform distribution for MPFR.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRUNIFORM_HPP)
#define RANDOMLIB_MPFRUNIFORM_HPP 1
#include <RandomLib/MPFRRandom.hpp>
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The uniform distribution for MPFR.
*
* This is just a thin layer on top of MPFRRandom to provide random numbers
* uniformly distributed in [0,1].
*
* This class uses a mutable private object. So a single MPFRUniform object
* cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRUniform object.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 32> class MPFRUniform {
public:
/**
* Initialize the MPFRUniform object.
**********************************************************************/
MPFRUniform() {};
/**
* Sample from the uniform distribution in [0,1] returning a MPFRRandom.
* This function takes an unused GMP random generator as a parameter, in
* order to parallel the usage of MPFRExponential and MPFRNormal.
*
* @param[out] t the MPFRRandom result.
* @param[in,out] r a GMP random generator (unused).
**********************************************************************/
void operator()(MPFRRandom<bits>& t, gmp_randstate_t r) const
{ Compute(r); _x.swap(t); }
/**
* Sample from the uniform distribution in [0,1].
*
* @param[out] val the sample from the uniform distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
{ Compute(r); return _x(val, r, round); }
private:
// disable copy constructor and assignment operator
MPFRUniform(const MPFRUniform&);
MPFRUniform& operator=(const MPFRUniform&);
void Compute(gmp_randstate_t /* r */) const { _x. Init(); }
mutable MPFRRandom<bits> _x;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRUNIFORM_HPP

View File

@ -0,0 +1,114 @@
/**
* \file NormalDistribution.hpp
* \brief Header for NormalDistribution
*
* Compute normal deviates.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_NORMALDISTRIBUTION_HPP)
#define RANDOMLIB_NORMALDISTRIBUTION_HPP 1
#include <cmath> // for std::log
namespace RandomLib {
/**
* \brief Normal deviates
*
* Sample from the normal distribution.
*
* This uses the ratio method; see Knuth, TAOCP, Vol 2, Sec. 3.4.1.C,
* Algorithm R. Unlike the Box-Muller method which generates two normal
* deviates at a time, this method generates just one. This means that this
* class has no state that needs to be saved when checkpointing a
* calculation. Original citation is\n A. J. Kinderman, J. F. Monahan,\n
* Computer Generation of Random Variables Using the Ratio of Uniform
* Deviates,\n ACM TOMS 3, 257--260 (1977).
*
* Improved "quadratic" bounds are given by\n J. L. Leva,\n A Fast Normal
* Random Number Generator,\n ACM TOMS 18, 449--453 and 454--455
* (1992).
*
* The log is evaluated 1.369 times per normal deviate with no bounds, 0.232
* times with Knuth's bounds, and 0.012 times with the quadratic bounds.
* Time is approx 0.3 us per deviate (1GHz machine, optimized, RealType =
* float).
*
* Example
* \code
* #include <RandomLib/NormalDistribution.hpp>
*
* RandomLib::Random r;
* std::cout << "Seed set to " << r.SeedString() << "\n";
* RandomLib::NormalDistribution<double> normdist;
* std::cout << "Select from normal distribution:";
* for (size_t i = 0; i < 10; ++i)
* std::cout << " " << normdist(r);
* std::cout << "\n";
* \endcode
*
* @tparam RealType the real type of the results (default double).
**********************************************************************/
template<typename RealType = double> class NormalDistribution {
public:
/**
* The type returned by NormalDistribution::operator()(Random&)
**********************************************************************/
typedef RealType result_type;
/**
* Return a sample of type RealType from the normal distribution with mean
* &mu; and standard deviation &sigma;.
*
* For &mu; = 0 and &sigma; = 1 (the defaults), the distribution is
* symmetric about zero and is nonzero. The maximum result is less than 2
* sqrt(log(2) \e p) where \e p is the precision of real type RealType.
* The minimum positive value is approximately 1/2<sup><i>p</i>+1</sup>.
* Here \e p is the precision of real type RealType.
*
* @tparam Random the type of RandomCanonical generator.
* @param[in,out] r the RandomCanonical generator.
* @param[in] mu the mean value of the normal distribution (default 0).
* @param[in] sigma the standard deviation of the normal distribution
* (default 1).
* @return the random sample.
**********************************************************************/
template<class Random>
RealType operator()(Random& r, RealType mu = RealType(0),
RealType sigma = RealType(1)) const throw();
};
template<typename RealType> template<class Random> inline RealType
NormalDistribution<RealType>::operator()(Random& r, RealType mu,
RealType sigma) const throw() {
// N.B. These constants can be regarded as "exact", so that the same number
// of significant figures are used in all versions. (They serve to
// "bracket" the real boundary specified by the log expression.)
const RealType
m = RealType( 1.7156 ), // sqrt(8/e) (rounded up)
s = RealType( 0.449871), // Constants from Leva
t = RealType(-0.386595),
a = RealType( 0.19600 ),
b = RealType( 0.25472 ),
r1 = RealType( 0.27597 ),
r2 = RealType( 0.27846 );
RealType u, v, Q;
do { // This loop is executed 1.369 times on average
// Pick point P = (u, v)
u = r.template FixedU<RealType>(); // Sample u in (0,1]
v = m * r.template FixedS<RealType>(); // Sample v in (-m/2, m/2); avoid 0
// Compute quadratic form Q
const RealType x = u - s;
const RealType y = (v < 0 ? -v : v) - t; // Sun has no long double abs!
Q = x*x + y * (a*y - b*x);
} while ( Q >= r1 && // accept P if Q < r1
( Q > r2 || // reject P if Q > r2
v*v > - 4 * u*u * std::log(u) ) ); // accept P if v^2 <= ...
return mu + sigma * (v / u); // return the slope of P (note u != 0)
}
} // namespace RandomLib
#endif // RANDOMLIB_NORMALDISTRIBUTION_HPP

View File

@ -0,0 +1,141 @@
/**
* \file Random.hpp
* \brief Header for Random, RandomGenerator.
*
* This loads up the header for RandomCanonical, RandomEngine, etc., to
* provide access to random integers of various sizes, random reals with
* various precisions, a random probability, etc.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOM_HPP)
#define RANDOMLIB_RANDOM_HPP 1
#include <RandomLib/Config.h>
#if defined(_MSC_VER)
typedef unsigned uint32_t;
typedef unsigned long long uint64_t;
#else
#include <stdint.h>
#endif
/**
* Use table, Power2::power2, for pow2? This isn't necessary with g++ 4.0
* because calls to std::pow are optimized. g++ 4.1 seems to have lost this
* capability though! And it's back in g++ 4.4. So, for simplicity, assume
* that all "current" versions of g++ perform the optimization.
**********************************************************************/
#if !defined(RANDOMLIB_POWERTABLE)
#if defined(__GNUC__)
#define RANDOMLIB_POWERTABLE 0
#else
// otherwise use a lookup table
#define RANDOMLIB_POWERTABLE 1
#endif
#endif
#if !HAVE_LONG_DOUBLE || defined(_MSC_VER)
#define RANDOMLIB_LONGDOUBLEPREC 53
#elif defined(__sparc)
#define RANDOMLIB_LONGDOUBLEPREC 113
#else
/**
* The precision of long doubles, used for sizing Power2::power2. 64 on
* Linux/Intel, 106 on MaxOS/PowerPC
**********************************************************************/
#define RANDOMLIB_LONGDOUBLEPREC __LDBL_MANT_DIG__
#endif
/**
* A compile-time assert. Use C++11 static_assert, if available.
**********************************************************************/
#if !defined(STATIC_ASSERT)
# if __cplusplus >= 201103
# define STATIC_ASSERT static_assert
# elif defined(__GXX_EXPERIMENTAL_CXX0X__)
# define STATIC_ASSERT static_assert
# elif defined(_MSC_VER) && _MSC_VER >= 1600
# define STATIC_ASSERT static_assert
# else
# define STATIC_ASSERT(cond,reason) \
{ enum{ STATIC_ASSERT_ENUM = 1/int(cond) }; }
# endif
#endif
/**
* Are denormalized reals of type RealType supported?
**********************************************************************/
#define RANDOMLIB_HASDENORM(RealType) 1
#if defined(_MSC_VER) && defined(RANDOMLIB_SHARED_LIB) && RANDOMLIB_SHARED_LIB
# if RANDOMLIB_SHARED_LIB > 1
# error RANDOMLIB_SHARED_LIB must be 0 or 1
# elif defined(RandomLib_EXPORTS)
# define RANDOMLIB_EXPORT __declspec(dllexport)
# else
# define RANDOMLIB_EXPORT __declspec(dllimport)
# endif
#else
# define RANDOMLIB_EXPORT
#endif
#include <stdexcept>
/**
* \brief Namespace for %RandomLib
*
* All of %RandomLib is defined within the RandomLib namespace. In addtiion
* all the header files are included via %RandomLib/filename. This minimizes
* the likelihood of conflicts with other packages.
**********************************************************************/
namespace RandomLib {
/**
* \brief Exception handling for %RandomLib
*
* A class to handle exceptions. It's derived from std::runtime_error so it
* can be caught by the usual catch clauses.
**********************************************************************/
class RandomErr : public std::runtime_error {
public:
/**
* Constructor
*
* @param[in] msg a string message, which is accessible in the catch
* clause, via what().
**********************************************************************/
RandomErr(const std::string& msg) : std::runtime_error(msg) {}
};
} // namespace RandomLib
#include <RandomLib/RandomCanonical.hpp>
#if !defined(RANDOMLIB_BUILDING_LIBRARY)
namespace RandomLib {
#if !defined(RANDOMLIB_DEFAULT_GENERATOR)
#define RANDOMLIB_DEFAULT_GENERATOR SRandomGenerator32
#endif
/**
* Point Random to one of a specific MT19937 generators.
**********************************************************************/
typedef RANDOMLIB_DEFAULT_GENERATOR RandomGenerator;
/**
* Hook Random to RandomGenerator
**********************************************************************/
typedef RandomCanonical<RandomGenerator> Random;
} // namespace RandomLib
#endif // !defined(RANDOMLIB_BUILDING_LIBRARY)
#endif // RANDOMLIB_RANDOM_HPP

View File

@ -0,0 +1,384 @@
/**
* \file RandomAlgorithm.hpp
* \brief Header for MT19937 and SFMT19937.
*
* This provides an interface to the Mersenne Twister
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
* MT19937</a> and SIMD oriented Fast Mersenne Twister
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html">
* SFMT19937</a> random number engines.
*
* Interface routines written by Charles Karney <charles@karney.com> and
* licensed under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMALGORITHM_HPP)
#define RANDOMLIB_RANDOMALGORITHM_HPP 1
#include <RandomLib/RandomType.hpp>
#include <stdexcept>
#include <string>
#if defined(HAVE_SSE2) && HAVE_SSE2
#include <emmintrin.h>
#endif
#if (defined(HAVE_SSE2) && HAVE_SSE2) && (defined(HAVE_ALTIVEC) && HAVE_ALTIVEC)
#error "HAVE_SSE2 and HAVE_ALTIVEC should not both be defined"
#endif
#if defined(_MSC_VER)
// Squelch warnings about casts truncating constants
# pragma warning (push)
# pragma warning (disable: 4310)
#endif
namespace RandomLib {
/**
* \brief The %MT19937 random number engine.
*
* This provides an interface to Mersenne Twister random number engine,
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
* MT19937</a>. See\n Makoto Matsumoto and Takuji Nishimura,\n Mersenne
* Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number
* Generator,\n ACM TOMACS 8, 3--30 (1998)
*
* This is adapted from the 32-bit and 64-bit C versions available at
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html and
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html
*
* The template argument give the type \e RandomType of the "natural" result.
* This incorporates the bit width and the C++ type of the result. Although
* the two versions of MT19937 produce different sequences, the
* implementations here are portable across 32-bit and 64-bit architectures.
*
* The class chiefly supplies the method for advancing the state by
* Transition.
*
* @tparam RandomType the type of the results, either Random_u32 or
* Random_u64.
*
* Interface routines written by Charles Karney <charles@karney.com> and
* licensed under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
template<class RandomType> class RANDOMLIB_EXPORT MT19937 {
public:
/**
* The result RandomType
**********************************************************************/
typedef RandomType engine_t;
/**
* The internal numeric type for MT19337::Transition
**********************************************************************/
typedef typename engine_t::type internal_type;
private:
/**
* The unsigned type of engine_t
**********************************************************************/
typedef typename engine_t::type engine_type;
/**
* The width of the engine_t
**********************************************************************/
static const unsigned width = engine_t::width;
enum {
/**
* The Mersenne prime is 2<sup><i>P</i></sup> &minus; 1
**********************************************************************/
P = 19937,
/**
* The short lag for MT19937
**********************************************************************/
M = width == 32 ? 397 : 156,
/**
* The number of ignored bits in the first word of the state
**********************************************************************/
R = ((P + width - 1)/width) * width - P
};
static const engine_type mask = engine_t::mask;
/**
* Magic matrix for MT19937
**********************************************************************/
static const engine_type magic =
width == 32 ? 0x9908b0dfULL : 0xb5026f5aa96619e9ULL;
/**
* Mask for top \e width &minus; \e R bits of a word
**********************************************************************/
static const engine_type upper = mask << R & mask;
/**
* Mask for low \e R bits of a <i>width</i>-bit word
**********************************************************************/
static const engine_type lower = ~upper & mask;
public:
/**
* A version number "EnMT" or "EnMU" to ensure safety of Save/Load. This
* needs to be unique across RandomAlgorithms.
**********************************************************************/
static const unsigned version = 0x456e4d54UL + (engine_t::width/32 - 1);
enum {
/**
* The size of the state. This is the long lag for MT19937.
**********************************************************************/
N = (P + width - 1)/width
};
/**
* Advance state by \e count batches. For speed all \e N words of state
* are advanced together. If \e count is negative, the state is stepped
* backwards. This is the meat of the MT19937 engine.
*
* @param[in] count how many batches to advance.
* @param[in,out] statev the internal state of the random number generator.
**********************************************************************/
static void Transition(long long count, internal_type statev[]) throw();
/**
* Manipulate a word of the state prior to output.
*
* @param[in] y a word of the state.
* @return the result.
**********************************************************************/
static engine_type Generate(engine_type y) throw();
/**
* Convert an arbitrary state into a legal one. This consists of (a)
* turning on one bit if the state is all zero and (b) making 31 bits of
* the state consistent with the other 19937 bits.
*
* @param[in,out] state the state of the generator.
**********************************************************************/
static void NormalizeState(engine_type state[]) throw();
/**
* Check that the state is legal, throwing an exception if it is not. At
* the same time, accumulate a checksum of the state.
*
* @param[in] state the state of the generator.
* @param[in,out] check an accumulated checksum.
**********************************************************************/
static void CheckState(const engine_type state[], Random_u32::type& check);
/**
* Return the name of the engine
*
* @return the name.
**********************************************************************/
static std::string Name() throw() {
return "MT19937<Random_u" + std::string(width == 32 ? "32" : "64") + ">";
}
};
/// \cond SKIP
template<>
inline Random_u32::type MT19937<Random_u32>::Generate(engine_type y) throw() {
y ^= y >> 11;
y ^= y << 7 & engine_type(0x9d2c5680UL);
y ^= y << 15 & engine_type(0xefc60000UL);
y ^= y >> 18;
return y;
}
template<>
inline Random_u64::type MT19937<Random_u64>::Generate(engine_type y) throw() {
// Specific tempering instantiation for width = 64 given in
// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html
y ^= y >> 29 & engine_type(0x5555555555555555ULL);
y ^= y << 17 & engine_type(0x71d67fffeda60000ULL);
y ^= y << 37 & engine_type(0xfff7eee000000000ULL);
y ^= y >> 43;
return y;
}
/// \endcond
/**
* \brief The SFMT random number engine.
*
* This provides an implementation of the SIMD-oriented Fast Mersenne Twister
* random number engine,
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html">
* SFMT</a>. See\n Mutsuo Saito,\n An Application of Finite Field: Design
* and Implementation of 128-bit Instruction-Based Fast Pseudorandom Number
* Generator,\n Master's Thesis, Dept. of Math., Hiroshima University
* (Feb. 2007).\n
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/M062821.pdf
* Mutsuo Saito and Makoto Matsumoto,\n
* SIMD-oriented Fast Mersenne Twister: a 128-bit Pseudorandom Number
* Generator,\n accepted in the proceedings of MCQMC2006\n
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/sfmt.pdf
*
* The template argument gives the type \e RandomType of the "natural"
* result. This incorporates the bit width and the C++ type of the result.
* The 32-bit and 64-bit versions of SFMT19937 produce the same sequences and
* the differing only in whether how the state is represented. The
* implementation includes a version using 128-bit SSE2 instructions. On
* machines without these instructions, portable implementations using
* traditional operations are provided. With the same starting seed,
* SRandom32::Ran64() and SRandom64::Ran64() produces the same sequences.
* Similarly SRandom64::Ran32() produces every other member of the sequence
* produced by SRandom32::Ran32().
*
* The class chiefly supplies the method for advancing the state by
* Transition.
*
* @tparam RandomType the type of the results, either Random_u32 or
* Random_u64.
*
* Written by Charles Karney <charles@karney.com> and licensed under the
* MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
template<class RandomType> class RANDOMLIB_EXPORT SFMT19937 {
public:
/**
* The result RandomType
**********************************************************************/
typedef RandomType engine_t;
#if defined(HAVE_SSE2) && HAVE_SSE2
typedef __m128i internal_type;
#elif defined(HAVE_ALTIVEC) && HAVE_ALTIVEC
typedef vector unsigned internal_type;
#else
/**
* The internal numeric type for SFMT19337::Transition
**********************************************************************/
typedef typename engine_t::type internal_type;
#endif
private:
/**
* The unsigned type of engine_t
**********************************************************************/
typedef typename engine_t::type engine_type;
/**
* The width of the engine_t
**********************************************************************/
static const unsigned width = engine_t::width;
enum {
/**
* The Mersenne prime is 2<sup><i>P</i></sup> &minus; 1
**********************************************************************/
P = 19937,
/**
* The long lag for SFMT19937 in units of 128-bit words
**********************************************************************/
N128 = (P + 128 - 1)/128,
/**
* How many width words per 128-bit word.
**********************************************************************/
R = 128 / width,
/**
* The short lag for SFMT19937 in units of 128-bit words
**********************************************************************/
M128 = 122,
/**
* The short lag for SFMT19937
**********************************************************************/
M = M128 * R
};
#if (defined(HAVE_SSE2) && HAVE_SSE2) || (defined(HAVE_ALTIVEC) && HAVE_ALTIVEC)
static const Random_u32::type magic0 = 0x1fffefUL;
static const Random_u32::type magic1 = 0x1ecb7fUL;
static const Random_u32::type magic2 = 0x1affffUL;
static const Random_u32::type magic3 = 0x1ffff6UL;
#else
/**
* Magic matrix for SFMT19937. Only the low 21 (= 32 &minus; 11) bits need
* to be set. (11 is the right shift applied to the words before masking.
**********************************************************************/
static const engine_type
magic0 = width == 32 ? 0x1fffefULL : 0x1ecb7f001fffefULL;
static const engine_type
magic1 = width == 32 ? 0x1ecb7fULL : 0x1ffff6001affffULL;
static const engine_type
magic2 = width == 32 ? 0x1affffULL : 0ULL;
static const engine_type
magic3 = width == 32 ? 0x1ffff6ULL : 0ULL;
#endif
/**
* Mask for simulating u32 << 18 with 64-bit words
**********************************************************************/
static const engine_type mask18 = engine_type(0xfffc0000fffc0000ULL);
/**
* Magic constants needed by "period certification"
**********************************************************************/
static const engine_type PARITY0 = 1U;
static const engine_type PARITY1 = width == 32 ? 0U : 0x13c9e68400000000ULL;
static const engine_type PARITY2 = 0U;
static const engine_type PARITY3 = width == 32 ? 0x13c9e684UL : 0U;
/**
* Least significant bit of PARITY
**********************************************************************/
static const unsigned PARITY_LSB = 0;
static const engine_type mask = engine_t::mask;
public:
/**
* A version number "EnSM" or "EnSN" to ensure safety of Save/Load. This
* needs to be unique across RandomAlgorithms.
**********************************************************************/
static const unsigned version = 0x456e534dUL + (engine_t::width/32 - 1);
enum {
/**
* The size of the state. The long lag for SFMT19937
**********************************************************************/
N = N128 * R
};
/**
* Advance state by \e count batches. For speed all \e N words of state
* are advanced together. If \e count is negative, the state is stepped
* backwards. This is the meat of the SFMT19937 engine.
*
* @param[in] count how many batches to advance.
* @param[in,out] statev the internal state of the random number generator.
**********************************************************************/
static void Transition(long long count, internal_type statev[])
throw();
/**
* Manipulate a word of the state prior to output. This is a no-op for
* SFMT19937.
*
* @param[in] y a word of the state.
* @return the result.
**********************************************************************/
static engine_type Generate(engine_type y) throw() { return y; }
/**
* Convert an arbitrary state into a legal one. This consists a "period
* certification to ensure that the period of the generator is at least
* 2<sup><i>P</i></sup> &minus; 1.
*
* @param[in,out] state the state of the generator.
**********************************************************************/
static void NormalizeState(engine_type state[]) throw();
/**
* Check that the state is legal, throwing an exception if it is not. This
* merely verifies that the state is not all zero. At the same time,
* accumulate a checksum of the state.
*
* @param[in] state the state of the generator.
* @param[in,out] check an accumulated checksum.
**********************************************************************/
static void CheckState(const engine_type state[], Random_u32::type& check);
/**
* Return the name of the engine
*
* @return the name.
**********************************************************************/
static std::string Name() throw() {
return "SFMT19937<Random_u" +
std::string(width == 32 ? "32" : "64") + ">";
}
};
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_RANDOMALGORITHM_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,640 @@
/**
* \file RandomEngine.hpp
* \brief Header for RandomEngine.
*
* Copyright (c) Charles Karney (2006-2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMENGINE_HPP)
#define RANDOMLIB_RANDOMENGINE_HPP 1
#include <RandomLib/RandomSeed.hpp>
#include <RandomLib/RandomAlgorithm.hpp>
#include <RandomLib/RandomMixer.hpp>
#include <limits>
#include <string>
#include <algorithm>
#if defined(HAVE_SSE2) && HAVE_SSE2 && defined(_MSC_VER) && !defined(_WIN64)
#include <new>
#endif
#if !defined(RANDOMLIB_BUILDING_LIBRARY) && \
defined(HAVE_BOOST_SERIALIZATION) && HAVE_BOOST_SERIALIZATION
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/vector.hpp>
#endif
namespace RandomLib {
/**
* \brief Uniform random number generator.
*
* This implements a generic random number generator. Such a generator
* requires two data holders RandomSeed, to hold the seed, and RandomEngine,
* to hold the state. In addition we need two piece of machinery, a "Mixer"
* to convert the seed into an initial state and an "Algorithm" to advance the
* state.
*
* @tparam Algorithm the random number algorithm.
* @tparam Mixer the way seeds are turned into state.
*
* RandomSeed is responsible for setting and reporting the seed.
*
* Mixer has no state and implements only static methods. It needs to have
* the following public interface
* - typedef mixer_t: a RandomType giving the output type
* - unsigned version: an identifying version number
* - static std::string Name(): an identifying name for the mixer
* - static method SeedToState: converts a seed into n words of state.
*
* Algorithm has no state and implements only static methods. It needs to
* have the following public interface
* - typedef engine_t: a RandomType giving the output type
* - typedef internal_type: a integer type used by Transition. This is
* usually the same as engine_t::type. However it allows the use of
* vector instructions on some platforms. We require that engine_t::type
* and internal_type line up properly in a union so that there is no need
* to convert the data explicitly between internal_type and
* engine_t::type.
* - unsigned version: an identifying version number
* - static std::string Name(): an identifying name for the mixer
* - enum N: the size of the state in units of engine_t.
* - static method Transition: steps the generator forwards or backwards.
* - static method Generate: tempers the state immediately prior to output
* - static method NormalizeState: force the initial state (the result of
* the Mixer) into a legal state.
* - static method CheckState accumulates the checksum for the state into
* check. In addition it throws an exception if the state is bad.
*
* RandomEngine is the glue that holds everything together. It repacks
* the mixer_t data from Mixer into engine_t if necessary. It deals with
* delivering individual random results, stepping the state forwards and
* backwards, leapfrogging the generator, I/O of the generator, etc.
*
* Written by Charles Karney <charles@karney.com> and licensed under the
* MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
template<class Algorithm, class Mixer>
class RANDOMLIB_EXPORT RandomEngine : public RandomSeed {
private:
/**
* The result RandomType (carried over from the \e Algorithm).
**********************************************************************/
typedef typename Algorithm::engine_t result_t;
/**
* The RandomType used by the \e Mixer.
**********************************************************************/
typedef typename Mixer::mixer_t mixer_t;
/**
* The internal_type used by the Algorithm::Transition().
**********************************************************************/
typedef typename Algorithm::internal_type engine_type;
public:
/**
* The number of random bits produced by Ran().
**********************************************************************/
enum {
width = result_t::width
};
/**
* A type large enough to hold \e width bits. This is used for the
* internal state of the generator and the result returned by Ran().
**********************************************************************/
typedef typename result_t::type result_type;
/**
* The minimum result returned by Ran() = 0.
**********************************************************************/
static const result_type min = result_t::min;
/**
* The maximum result returned by Ran() = 2<sup><i>w</i></sup> &minus; 1.
**********************************************************************/
static const result_type max = result_t::max;
protected:
/**
* The mask for the result_t.
**********************************************************************/
static const result_type mask = result_t::mask;
private:
/**
* A version number "RandLib0" to ensure safety of Save/Load. The first 7
* bytes can be regarded as a "signature" and the 8th byte a version
* number.
**********************************************************************/
static const u64::type version = 0x52616e644c696230ULL; // 'RandLib0'
/**
* Marker for uninitialized object
**********************************************************************/
static const unsigned UNINIT = 0xffffffffU;
enum {
/**
* The size of the state in units of result_type
**********************************************************************/
N = Algorithm::N,
/**
* The size of the state in units of mixer_t::type
**********************************************************************/
NU = (N * width + mixer_t::width - 1) / mixer_t::width,
/**
* The size of the state in units of engine_type.
**********************************************************************/
NV = N * sizeof(result_type) / sizeof(engine_type)
};
/**
* \brief Union for the state.
*
* A union to hold the state in the result_type, mixer_t::type, and
* engine_type representations.
**********************************************************************/
union {
/**
* the result_type representation returned by Ran()
**********************************************************************/
result_type _state[N];
/**
* the mixer_t::type representation returned by Mixer::SeedToState.
**********************************************************************/
typename mixer_t::type _stateu[NU];
/**
* the engine_type representation returned by Algorithm::Transition.
**********************************************************************/
engine_type _statev[NV];
};
/**
* The index for the next random value
**********************************************************************/
unsigned _ptr;
/**
* How many times has Transition() been called
**********************************************************************/
long long _rounds;
/**
* Stride for leapfrogging
**********************************************************************/
unsigned _stride;
public:
/**
* \name Constructors
**********************************************************************/
///@{
/**
* Initialize from a vector. Only the low \e 32 bits of each element are
* used.
*
* @tparam IntType the integral type of the elements of the vector.
* @param[in] v the vector of elements.
**********************************************************************/
template<typename IntType>
explicit RandomEngine(const std::vector<IntType>& v) { Reseed(v); }
/**
* Initialize from a pair of iterators setting seed to [\e a, \e b). The
* iterator must produce results which can be converted into seed_type.
* Only the low \e 32 bits of each element are used.
*
* @tparam InputIterator the type of the iterator.
* @param[in] a the beginning iterator.
* @param[in] b the ending iterator.
**********************************************************************/
template<typename InputIterator>
RandomEngine(InputIterator a, InputIterator b) { Reseed(a, b); }
/**
* Initialize with seed [\e n]. Only the low \e width bits of \e n are
* used.
*
* @param[in] n the new seed to use.
**********************************************************************/
explicit RandomEngine(seed_type n) { Reseed(n); }
/**
* Initialize with seed []. This can be followed by a call to Reseed() to
* select a unique seed.
**********************************************************************/
RandomEngine() { unsigned long s[1]; Reseed(s, s); }
/**
* Initialize from a string. See Reseed(const std::string& s)
*
* @param[in] s the string to be decoded into a seed.
**********************************************************************/
explicit RandomEngine(const std::string& s) { Reseed(s); }
///@}
/**
* \name Functions for returning random data
**********************************************************************/
///@{
/**
* Return \e width bits of randomness. This is the natural unit of random
* data produced random number generator.
*
* @return the next random number of width \e width.
**********************************************************************/
result_type Ran() throw() {
if (_ptr >= N)
Next();
result_type y = _state[_ptr];
_ptr += _stride;
return Algorithm::Generate(y);
}
/**
* Return 32 bits of randomness.
*
* @return a 32-bit random number.
**********************************************************************/
u32::type Ran32() throw() {
// return width > 32 ? u32::cast(Ran()) : Ran();
return u32::cast(Ran());
}
/**
* Return 64 bits of randomness.
*
* @return a 64-bit random number.
**********************************************************************/
u64::type Ran64() throw() {
const u64::type x = Ran();
return width > 32 ? x : u64::cast(Ran()) << (64 - width) | x;
}
/**
* Return \e width bits of randomness. Result is in [0,
* 2<sup><i>w</i></sup>). (This just calls Ran().)
*
* @return the next random number of width \e width.
**********************************************************************/
result_type operator()() throw() { return Ran(); }
///@}
#if defined(HAVE_SSE2) && HAVE_SSE2 && defined(_MSC_VER) && !defined(_WIN64)
/**
* new operator with alignment (needed for Visual Studio)
**********************************************************************/
void* operator new(size_t n) {
void* p = _aligned_malloc(n, __alignof(RandomEngine));
if (p == 0) throw std::bad_alloc();
return p;
}
/**
* delete operator with alignment (needed for Visual Studio)
**********************************************************************/
void operator delete(void* p) { _aligned_free(p); }
/**
* new[] operator with alignment (needed for Visual Studio)
**********************************************************************/
void* operator new[](size_t n) {
void* p = _aligned_malloc(n, __alignof(RandomEngine));
if (p == 0) throw std::bad_alloc();
return p;
}
/**
* delete[] operator with alignment (needed for Visual Studio)
**********************************************************************/
void operator delete[](void* p) { _aligned_free(p); }
#endif
/**
* \name Comparing Random objects
**********************************************************************/
///@{
/**
* Test equality of two Random objects. This test that the seeds match and
* that they have produced the same number of random numbers.
*
* @param[in] r the RandomEngine object to compare.
* @return true if the RandomEngine objects produce the same results.
**********************************************************************/
bool operator==(const RandomEngine& r) const throw()
// Ensure that the two Random objects behave the same way. Note however
// that the internal states may still be different, e.g., the following all
// result in Random objects which are == (with Count() == 0) but which all
// have different internal states:
//
// Random r(0); _ptr == UNINIT
// r.StepCount( 1); r.StepCount(-1); _ptr == 0, _rounds == 0
// r.StepCount(-1); r.StepCount( 1); _ptr == N, _rounds == -1
{ return Count() == r.Count() && _seed == r._seed &&
_stride == r._stride; }
/**
* Test inequality of two Random objects. See Random::operator==
*
* @param[in] r the RandomEngine object to compare.
* @return true if the RandomEngine objects produce different results.
**********************************************************************/
bool operator!=(const RandomEngine& r) const throw()
{ return !operator==(r); }
///@}
/**
* \name Interchanging Random objects
**********************************************************************/
///@{
/**
* Swap with another Random object.
*
* @param[in,out] t the RandomEngine object to swap with.
**********************************************************************/
void swap(RandomEngine& t) throw() {
_seed.swap(t._seed);
std::swap(_ptr, t._ptr);
std::swap(_stride, t._stride);
std::swap(_rounds, t._rounds);
std::swap_ranges(_state, _state + N, t._state);
}
///@}
/**
* \name Writing to and reading from a stream
**********************************************************************/
///@{
/**
* Save the state of the Random object to an output stream. Format is a
* sequence of unsigned 32-bit integers written either in decimal (\e bin
* false, text format) or in network order with most significant byte first
* (\e bin true, binary format). Data consists of:
*
* - RandomLib magic string + version (2 words)
* - Algorithm version (1 word)
* - Mixer version (1 word)
* - _seed.size() (1 word)
* - _seed data (_seed.size() words)
* - _ptr (1 word)
* - _stride (1 word)
* - if _ptr != UNINIT, _rounds (2 words)
* - if _ptr != UNINIT, _state (N words or 2 N words)
* - checksum
*
* Shortest possible saved result consists of 8 words. This corresponds to
* RandomSeed() = [] and Count() = 0.
*
* @param[in,out] os the output stream.
* @param[in] bin if true (the default) save in binary mode.
**********************************************************************/
void Save(std::ostream& os, bool bin = true) const;
/**
* Restore the state of the Random object from an input stream. If \e bin,
* read in binary, else use text format. See documentation of
* RandomEngine::Save for the format. Include error checking on data to
* make sure the input has not been corrupted. If an error occurs while
* reading, the Random object is unchanged.
*
* @param[in,out] is the input stream.
* @param[in] bin if true (the default) load in binary mode.
* @exception RandomErr if the state read from \e is is illegal.
**********************************************************************/
void Load(std::istream& is, bool bin = true) {
// Read state into temporary so as not to change object on error.
RandomEngine t(is, bin);
_seed.reserve(t._seed.size());
*this = t;
}
///@}
/**
* \name Basic I/O
**********************************************************************/
///@{
/**
* Write the state of a generator to stream \e os as text
*
* @param[in,out] os the output stream.
* @param[in] r the RandomEngine object to be saved.
**********************************************************************/
friend std::ostream& operator<<(std::ostream& os, const RandomEngine& r) {
r.Save(os, false);
return os;
}
/**
* Read the state of a generator from stream \e is as text
*
* @param[in,out] is the output stream.
* @param[in] r the RandomEngine object to be loaded.
* @exception RandomErr if the state read from \e is is illegal.
**********************************************************************/
friend std::istream& operator>>(std::istream& is, RandomEngine& r) {
r.Load(is, false);
return is;
}
///@}
/**
* \name Examining and advancing the Random generator
**********************************************************************/
///@{
/**
* Return the number of random numbers used. This needs to return a long
* long result since it can reasonably exceed 2<sup>31</sup>. (On a 1GHz
* machine, it takes about a minute to produce 2<sup>32</sup> random
* numbers.) More precisely this is the (zero-based) index of the next
* random number to be produced. (This distinction is important when
* leapfrogging is in effect.)
*
* @return the count of random numbers used.
**********************************************************************/
long long Count() const throw()
{ return _ptr == UNINIT ? 0 : _rounds * N + _ptr; }
/**
* Step the generator forwards or backwards so that the value returned
* by Count() is \e n
*
* @param[in] n the new count.
**********************************************************************/
void SetCount(long long n) throw() { StepCount(n - Count()); }
/**
* Step the generator forward \e n steps. \e n can be negative.
*
* @param[in] n how much to step the generator forward.
**********************************************************************/
void StepCount(long long n) throw();
/**
* Resets the sequence. Equivalent to SetCount(0), but works by
* reinitializing the Random object from its seed, rather than by stepping
* the sequence backwards. In addition, this undoes leapfrogging.
**********************************************************************/
void Reset() throw() { _ptr = UNINIT; _stride = 1; }
///@}
/**
* \name Leapfrogging
**********************************************************************/
///@{
/**
* Set leapfrogging stride to a positive number \e n and increment Count()
* by \e k < \e n. If the current Count() is \e i, then normally the next
* 3 random numbers would have (zero-based) indices \e i, \e i + 1, \e i +
* 2, and the new Count() is \e i + 2. However, after SetStride(\e n, \e
* k) the next 3 random numbers have indices \e i + \e k, \e i + \e k + \e
* n, \e i + \e k + 2\e n, and the new Count() is \e i + \e k + 3\e n.
* With leapfrogging in effect, the time to produce raw random numbers is
* roughly proportional to 1 + (\e n &minus; 1)/3. Reseed(...) and Reset()
* both reset the stride back to 1. See \ref parallel for a description of
* how to use this facility.
*
* @param[in] n the stride (default 1).
* @param[in] k the initial increment (default 0).
* @exception RandomErr if \e n is 0 or too large or if \e k is not less
* than \e n.
**********************************************************************/
void SetStride(unsigned n = 1, unsigned k = 0) {
// Limit stride to UNINIT/2. This catches negative numbers that have
// been cast into unsigned. In reality the stride should be no more than
// 10-100.
if (n == 0 || n > UNINIT/2)
throw RandomErr("RandomEngine: Invalid stride");
if (k >= n)
throw RandomErr("RandomEngine: Invalid offset");
_stride = n;
StepCount(k);
}
/**
* Return leapfrogging stride.
*
* @return the stride.
**********************************************************************/
unsigned GetStride() const throw() { return _stride; }
///@}
/**
* Tests basic engine.
*
* @exception RandomErr if any of the tests fail.
**********************************************************************/
static void SelfTest();
/**
* Return the name of the generator. This incorporates the names of the \e
* Algorithm and \e Mixer.
*
* @return the name of the generator.
**********************************************************************/
static std::string Name() {
return "RandomEngine<" + Algorithm::Name() + "," + Mixer::Name() + ">";
}
private:
/**
* Compute initial state from seed
**********************************************************************/
void Init() throw();
/**
* The interface to Transition used by Ran().
**********************************************************************/
void Next() throw() {
if (_ptr == UNINIT)
Init();
_rounds += _ptr/N;
Algorithm::Transition(_ptr/N, _statev);
_ptr %= N;
}
u32::type Check(u64::type v, u32::type e, u32::type m) const;
static result_type SelfTestResult(unsigned) throw() { return 0; }
/**
* Read from an input stream. Potentially corrupts object. This private
* constructor is used by RandomEngine::Load so that it can avoid
* corrupting its state on bad input.
**********************************************************************/
explicit RandomEngine(std::istream& is, bool bin);
#if !defined(RANDOMLIB_BUILDING_LIBRARY) && \
defined(HAVE_BOOST_SERIALIZATION) && HAVE_BOOST_SERIALIZATION
friend class boost::serialization::access;
/**
* Save to a boost archive. Boost versioning isn't very robust. (It
* allows a RandomGenerator32 to be read back in as a RandomGenerator64.
* It doesn't interact well with templates.) So we do our own versioning
* and supplement this with a checksum.
**********************************************************************/
template<class Archive> void save(Archive& ar, const unsigned int) const {
u64::type _version = version;
u32::type _eversion = Algorithm::version,
_mversion = Mixer::version,
_checksum = Check(_version, _eversion, _mversion);
ar & boost::serialization::make_nvp("version" , _version )
& boost::serialization::make_nvp("eversion", _eversion)
& boost::serialization::make_nvp("mversion", _mversion)
& boost::serialization::make_nvp("seed" , _seed )
& boost::serialization::make_nvp("ptr" , _ptr )
& boost::serialization::make_nvp("stride" , _stride );
if (_ptr != UNINIT)
ar & boost::serialization::make_nvp("rounds", _rounds )
& boost::serialization::make_nvp("state" , _state );
ar & boost::serialization::make_nvp("checksum", _checksum);
}
/**
* Load from a boost archive. Do this safely so that the current object is
* not corrupted if the archive is bogus.
**********************************************************************/
template<class Archive> void load(Archive& ar, const unsigned int) {
u64::type _version;
u32::type _eversion, _mversion, _checksum;
ar & boost::serialization::make_nvp("version" , _version )
& boost::serialization::make_nvp("eversion", _eversion )
& boost::serialization::make_nvp("mversion", _mversion );
RandomEngine<Algorithm, Mixer> t(std::vector<seed_type>(0));
ar & boost::serialization::make_nvp("seed" , t._seed )
& boost::serialization::make_nvp("ptr" , t._ptr )
& boost::serialization::make_nvp("stride" , t._stride );
if (t._ptr != UNINIT)
ar & boost::serialization::make_nvp("rounds", t._rounds )
& boost::serialization::make_nvp("state" , t._state );
ar & boost::serialization::make_nvp("checksum", _checksum );
if (t.Check(_version, _eversion, _mversion) != _checksum)
throw RandomErr("RandomEngine: Checksum failure");
_seed.reserve(t._seed.size());
*this = t;
}
/**
* Glue the boost save and load functionality together---a bit of boost
* magic.
**********************************************************************/
template<class Archive>
void serialize(Archive &ar, const unsigned int file_version)
{ boost::serialization::split_member(ar, *this, file_version); }
#endif // HAVE_BOOST_SERIALIZATION
};
typedef RandomEngine<MT19937 <Random_u32>, MixerSFMT> MRandomGenerator32;
typedef RandomEngine<MT19937 <Random_u64>, MixerSFMT> MRandomGenerator64;
typedef RandomEngine<SFMT19937<Random_u32>, MixerSFMT> SRandomGenerator32;
typedef RandomEngine<SFMT19937<Random_u64>, MixerSFMT> SRandomGenerator64;
} // namespace RandomLib
namespace std {
/**
* Swap two RandomEngines. This is about 3x faster than the default swap.
*
* @tparam Algorithm the algorithm for the RandomEngine.
* @tparam Mixer the mixer for the RandomEngine.
* @param[in,out] r the first RandomEngine to swap.
* @param[in,out] s the second RandomEngine to swap.
**********************************************************************/
template<class Algorithm, class Mixer>
void swap(RandomLib::RandomEngine<Algorithm, Mixer>& r,
RandomLib::RandomEngine<Algorithm, Mixer>& s) throw() {
r.swap(s);
}
} // namespace std
#endif // RANDOMLIB_RANDOMENGINE_HPP

View File

@ -0,0 +1,258 @@
/**
* \file RandomMixer.hpp
* \brief Header for Mixer classes.
*
* Mixer classes convert a seed vector into a random generator state. An
* important property of this method is that "close" seeds should produce
* "widely separated" states. This allows the seeds to be set is some
* systematic fashion to produce a set of uncorrelated random number
* sequences.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMMIXER_HPP)
#define RANDOMLIB_RANDOMMIXER_HPP 1
#include <vector>
#include <string>
#include <RandomLib/RandomSeed.hpp>
namespace RandomLib {
/**
* \brief The original %MT19937 mixing functionality
*
* This implements the functionality of init_by_array in MT19937
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c
* and init_by_array64 in MT19937_64
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c
* with the following changes:
* - in the case of an zero-length seed array, behave in the same way if
* MT19937 and MT19937_64 are called without initialization in which case,
* e.g., init_genrand(5489UL) is called. (init_by_array does not allow
* calling with a zero-length seed.)
* - init_by_array64 accepts a seed array of 64-bit unsigned ints. Here with
* seed is an array of 32-bit unsigned ints and these are repacked into
* 64-bit quantities internally using a LSB convention. Thus, to mimic the
* MT19937_64 sample invocation with a seed array {0x12345ULL, 0x23456ULL,
* 0x34567ULL, 0x45678ULL}, MixerMT0<Random_u64>::SeedToState needs to
* be invoked with a seed vector [0x12345UL, 0, 0x23456UL, 0, 0x34567UL, 0,
* 0x45678UL, 0]. (Actually the last 0 is unnecessary.)
*
* The template parameter \e RandomType switches between the 32-bit and
* 64-bit versions.
*
* MixerMT0 is specific to the MT19937 generators and should not be used
* for other generators (e.g., SFMT19937). In addition, MixerMT0 has
* known defects and should only be used to check the operation of the
* MT19937 engines against the original implementation. These defects are
* described in the MixerMT1 which is a modification of MixerMT0
* which corrects these defects. For production use MixerMT1 or,
* preferably, MixerSFMT should be used.
*
* @tparam RandomType the type of the results, either Random_u32 or
* Random_u64.
**********************************************************************/
template<class RandomType> class RANDOMLIB_EXPORT MixerMT0 {
public:
/**
* The RandomType controlling the output of MixerMT0::SeedToState
**********************************************************************/
typedef RandomType mixer_t;
/**
* A version number which should be unique to this RandomMixer. This
* prevents RandomEngine::Load from loading a saved generator with a
* different RandomMixer. Here the version is "MxMT" or "MxMU".
**********************************************************************/
static const unsigned version = 0x4d784d54UL + (mixer_t::width == 64);
private:
/**
* The unsigned type corresponding to mixer_t.
**********************************************************************/
typedef typename mixer_t::type mixer_type;
/**
* The mask for mixer_t.
**********************************************************************/
static const mixer_type mask = mixer_t::mask;
public:
/**
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
* n.
*
* @param[in] seed the input seed vector.
* @param[out] state the generator state.
* @param[in] n the size of the state.
**********************************************************************/
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
mixer_type state[], unsigned n) throw();
/**
* Return the name of this class.
*
* @return the name.
**********************************************************************/
static std::string Name() {
return "MixerMT0<Random_u" +
std::string(mixer_t::width == 32 ? "32" : "64") + ">";
}
private:
static const mixer_type a0 = 5489ULL;
static const mixer_type a1 = 19650218ULL;
static const mixer_type
b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL;
static const mixer_type
c = mixer_t::width == 32 ? 1664525ULL : 3935559000370003845ULL;
static const mixer_type
d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL;
};
/**
* \brief The modified %MT19937 mixing functionality
*
* MixerMT0 has two defects
* - The zeroth word of the state is set to a constant (independent of the
* seed). This is a relatively minor defect which halves the accessible
* state space for MT19937 (but the resulting state space is still huge).
* (Actually, for the 64-bit version, it reduces the accessible states by
* 2<sup>33</sup>. On the other hand the 64-bit has better mixing
* properties.)
* - Close seeds, for example, [1] and [1,0], result in the same state. This
* is a potentially serious flaw which might result is identical random
* number sequences being generated instead of independent sequences.
*
* MixerMT1 fixes these defects in a straightforward manner. The
* resulting algorithm was included in one of the proposals for Random Number
* Generation for C++0X, see Brown, et al.,
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2079.pdf
*
* The template parameter \e RandomType switches between the 32-bit and
* 64-bit versions.
*
* MixerMT1 still has a weakness in that it doesn't thoroughly mix the
* state. This is illustrated by an example given to me by Makoto Matsumoto:
* Consider a seed of length \e N and suppose we consider all \e
* W<sup><i>N</i>/2</sup> values for the first half of the seed (here \e W =
* 2<sup><i>width</i></sup>). MixerMT1 has a bottleneck in the way that
* the state is initialized which results in the second half of the state
* only taking on \e W<sup>2</sup> possible values. MixerSFMT mixes the
* seed into the state much more thoroughly.
*
* @tparam RandomType the type of the results, either Random_u32 or
* Random_u64.
**********************************************************************/
template<class RandomType> class RANDOMLIB_EXPORT MixerMT1 {
public:
/**
* The RandomType controlling the output of MixerMT1::SeedToState
**********************************************************************/
typedef RandomType mixer_t;
/**
* A version number which should be unique to this RandomMixer. This
* prevents RandomEngine::Load from loading a saved generator with a
* different RandomMixer. Here the version is "MxMV" or "MxMW".
**********************************************************************/
static const unsigned version = 0x4d784d56UL + (mixer_t::width == 64);
private:
/**
* The unsigned type corresponding to mixer_t.
**********************************************************************/
typedef typename mixer_t::type mixer_type;
/**
* The mask for mixer_t.
**********************************************************************/
static const mixer_type mask = mixer_t::mask;
public:
/**
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
* n.
*
* @param[in] seed the input seed vector.
* @param[out] state the generator state.
* @param[in] n the size of the state.
**********************************************************************/
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
mixer_type state[], unsigned n) throw();
/**
* Return the name of this class.
*
* @return the name.
**********************************************************************/
static std::string Name() {
return "MixerMT1<Random_u" +
std::string(mixer_t::width == 32 ? "32" : "64") + ">";
}
private:
static const mixer_type a = 5489ULL;
static const mixer_type
b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL;
static const mixer_type
c = mixer_t::width == 32 ? 1664525ULL : 3935559000370003845ULL;
static const mixer_type
d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL;
};
/**
* \brief The SFMT mixing functionality
*
* MixerSFMT is adapted from SFMT's init_by_array Mutsuo Saito given in
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/SFMT-src-1.2.tar.gz
* and is part of the C++11 standard; see P. Becker, Working Draft, Standard
* for Programming Language C++, Oct. 2007, Sec. 26.4.7.1,
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
*
* MixerSFMT contains a single change is to allow it to function properly
* when the size of the state is small.
*
* MixerSFMT mixes the seed much more thoroughly than MixerMT1 and, in
* particular, it removes the mixing bottleneck present in MixerMT1.
* Thus it is the recommended mixing scheme for all production work.
**********************************************************************/
class RANDOMLIB_EXPORT MixerSFMT {
public:
/**
* The RandomType controlling the output of MixerSFMT::SeedToState
**********************************************************************/
typedef Random_u32 mixer_t;
/**
* A version number which should be unique to this RandomMixer. This
* prevents RandomEngine::Load from loading a saved generator with a
* different RandomMixer. Here the version is "MxSM".
**********************************************************************/
static const unsigned version = 0x4d78534dUL;
private:
/**
* The unsigned type corresponding to mixer_t.
**********************************************************************/
typedef mixer_t::type mixer_type;
/**
* The mask for mixer_t.
**********************************************************************/
static const mixer_type mask = mixer_t::mask;
public:
/**
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
* n.
*
* @param[in] seed the input seed vector.
* @param[out] state the generator state.
* @param[in] n the size of the state.
**********************************************************************/
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
mixer_type state[], unsigned n) throw();
/**
* Return the name of this class.
*
* @return the name.
**********************************************************************/
static std::string Name() { return "MixerSFMT"; }
private:
static const mixer_type a = 0x8b8b8b8bUL;
static const mixer_type b = 1664525UL;
static const mixer_type c = 1566083941UL;
};
} // namespace RandomLib
#endif // RANDOMLIB_RANDOMMIXER_HPP

View File

@ -0,0 +1,472 @@
/**
* \file RandomNumber.hpp
* \brief Header for RandomNumber
*
* Infinite precision random numbers.
*
* Copyright (c) Charles Karney (2006-2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMNUMBER_HPP)
#define RANDOMLIB_RANDOMNUMBER_HPP 1
#include <vector>
#include <iomanip>
#include <limits>
#include <cmath> // for std::pow
#include <RandomLib/UniformInteger.hpp>
namespace RandomLib {
/**
* \brief Infinite precision random numbers.
*
* Implement infinite precision random numbers. Integer part is non-random.
* Fraction part consists of any some number of digits in base
* 2<sup><i>b</i></sup>. If \e m digits have been generated then the
* fraction is uniformly distributed in the open interval
* &sum;<sub><i>k</i>=1</sub><sup><i>m</i></sup>
* <i>f</i><sub><i>k</i>&minus;1</sub>/2<sup><i>kb</i></sup> +
* (0,1)/2<sup><i>mb</i></sup>. When a RandomNumber is first constructed the
* integer part is zero and \e m = 0, and the number represents (0,1). A
* RandomNumber is able to represent all numbers in the symmetric open
* interval (&minus;2<sup>31</sup>, 2<sup>31</sup>). In this implementation,
* \e b must one of 1, 2, 3, 4, 8, 12, 16, 20, 24, 28, or 32. (This
* restriction allows printing in hexadecimal and can easily be relaxed.
* There's also no essential reason why the base should be a power of 2.)
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 1> class RandomNumber {
public:
/**
* Constructor sets number to a random number uniformly distributed in
* (0,1).
**********************************************************************/
RandomNumber() throw() : _n(0), _s(1) {}
/**
* Swap with another RandomNumber. This is a fast way of doing an
* assignment.
*
* @param[in,out] t the RandomNumber to swap with.
**********************************************************************/
void swap(RandomNumber& t) throw() {
if (this != &t) {
std::swap(_n, t._n);
std::swap(_s, t._s);
_f.swap(t._f);
}
}
/**
* Return to initial state, uniformly distributed in (0,1).
**********************************************************************/
void Init() throw() {
STATIC_ASSERT(bits > 0 && bits <= w && (bits < 4 || bits % 4 == 0),
"RandomNumber: unsupported value for bits");
_n = 0;
_s = 1;
_f.clear();
}
/**
* @return the sign of the RandomNumber (&plusmn; 1).
**********************************************************************/
int Sign() const throw() { return _s; }
/**
* Change the sign of the RandomNumber.
**********************************************************************/
void Negate() throw() { _s *= -1; }
/**
* @return the floor of the RandomNumber.
**********************************************************************/
int Floor() const throw() { return _s > 0 ? int(_n) : -1 - int(_n); }
/**
* @return the ceiling of the RandomNumber.
**********************************************************************/
int Ceiling() const throw() { return _s > 0 ? 1 + int(_n) : - int(_n); }
/**
* @return the unsigned integer component of the RandomNumber.
**********************************************************************/
unsigned UInteger() const throw() { return _n; }
/**
* Add integer \e k to the RandomNumber.
*
* @param[in] k the integer to add.
**********************************************************************/
void AddInteger(int k) throw() {
k += Floor(); // The new floor
int ns = k < 0 ? -1 : 1; // The new sign
if (ns != _s) // If sign changes, set f = 1 - f
for (size_t k = 0; k < Size(); ++k)
_f[k] = ~_f[k] & mask;
_n = ns > 0 ? k : -(k + 1);
}
/**
* Compare with another RandomNumber, *this &lt; \e t
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in,out] t a RandomNumber to compare.
* @return true if *this &lt; \e t.
**********************************************************************/
template<class Random> bool LessThan(Random& r, RandomNumber& t) {
if (this == &t) return false; // same object
if (_s != t._s) return _s < t._s;
if (_n != t._n) return (_s < 0) ^ (_n < t._n);
for (unsigned k = 0; ; ++k) {
// Impose an order on the evaluation of the digits.
const unsigned x = Digit(r,k);
const unsigned y = t.Digit(r,k);
if (x != y) return (_s < 0) ^ (x < y);
// Two distinct numbers are never equal
}
}
/**
* Compare RandomNumber with two others, *this &gt; max(\e u, \e v)
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in,out] u first RandomNumber to compare.
* @param[in,out] v second RandomNumber to compare.
* @return true if *this &gt; max(\e u, \e v).
**********************************************************************/
template<class Random> bool GreaterPair(Random& r,
RandomNumber& u, RandomNumber& v) {
// cmps is set to false as soon as u <= *this, and likewise for cmpt.
bool cmpu = this != &u, cmpv = this != &v && &u != &v;
if (!(cmpu || cmpv)) return true;
// Check signs first
if (cmpu) {
if (u._s > _s) return false; // u > *this
if (u._s < _s) cmpu = false;
}
if (cmpv) {
if (v._s > _s) return false; // v > *this
if (v._s < _s) cmpv = false;
}
if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this
// Check integer parts
if (cmpu) {
if ((_s < 0) ^ (u._n > _n)) return false; // u > *this
if ((_s < 0) ^ (u._n < _n)) cmpu = false;
}
if (cmpv) {
if ((_s < 0) ^ (v._n > _n)) return false; // v > *this
if ((_s < 0) ^ (v._n < _n)) cmpv = false;
}
if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this
// Check fractions
for (unsigned k = 0; ; ++k) {
// Impose an order on the evaluation of the digits. Note that this is
// asymmetric on interchange of u and v; since u is tested first, more
// digits of u are generated than v (on average).
const unsigned x = Digit(r,k);
if (cmpu) {
const unsigned y = u.Digit(r,k);
if ((_s < 0) ^ (y > x)) return false; // u > *this
if ((_s < 0) ^ (y < x)) cmpu = false;
}
if (cmpv) {
const unsigned y = v.Digit(r,k);
if ((_s < 0) ^ (y > x)) return false; // v > *this
if ((_s < 0) ^ (y < x)) cmpv = false;
}
if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this
}
}
/**
* Compare with a fraction, *this &lt; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &lt; <i>p</i>/<i>q</i>.
**********************************************************************/
template<class Random, typename IntType>
bool LessThan(Random& r, IntType p, IntType q) {
for (int k = 0;; ++k) {
if (p <= 0) return false;
if (p >= q) return true;
// Here p is in [1,q-1]. Need to avoid overflow in computation of
// (q-1)<<bits and (2^bits-1)*q
p = (p << bits) - Digit(r,k) * q;
}
}
/**
* Compare with a paritally sampled fraction
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p0 the starting point for the numerator.
* @param[in] c the stride for the fraction (require \e c &gt; 0).
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @param[in,out] j the increment for the numerator.
* @return true if *this &lt; (<i>p</i><sub>0</sub> + <i>cj</i>)/<i>q</i>.
**********************************************************************/
template<class Random, typename IntType>
bool LessThan(Random& r, IntType p0, IntType c, IntType q,
UniformInteger<IntType, bits>& j) {
for (int k = 0;; ++k) {
if (j. LessThanEqual(r, - p0, c)) return false;
if (j.GreaterThanEqual(r, q - p0, c)) return true;
p0 = (p0 << bits) - IntType(Digit(r,k)) * q;
c <<= bits;
}
}
/**
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] k the index of a digit of the fraction
* @return digit number \e k, generating it if necessary.
**********************************************************************/
template<class Random> unsigned Digit(Random& r, unsigned k) {
ExpandTo(r, k + 1);
return _f[k];
}
/**
* Add one digit to the fraction.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
**********************************************************************/
template<class Random> void AddDigit(Random& r)
{ _f.push_back(RandomDigit(r)); }
/**
* @param[in] k the index of a digit of the fraction
* @return a const reference to digit number \e k, without generating new
* digits.
* @exception std::out_of_range if the digit hasn't been generated.
**********************************************************************/
const unsigned& RawDigit(unsigned k) const throw()
{ return (const unsigned&)(_f.at(k)); }
/**
* @param[in] k the index of a digit of the fraction
* @return a non-const reference to digit number \e k, without generating
* new digits.
* @exception std::out_of_range if the digit hasn't been generated.
**********************************************************************/
unsigned& RawDigit(unsigned k) throw()
{ return (unsigned&)(_f.at(k)); }
/**
* Return to initial state, uniformly distributed in \e n + (0,1). This is
* similar to Init but also returns the memory used by the object to the
* system. Normally Init should be used.
**********************************************************************/
void Clear() {
std::vector<unsigned> z(0);
_n = 0;
_s = 1;
_f.swap(z);
}
/**
* @return the number of digits in fraction
**********************************************************************/
unsigned Size() const throw() { return unsigned(_f.size()); }
/**
* Return the fraction part of the RandomNumber as a floating point number
* of type RealType rounded to the nearest multiple of
* 1/2<sup><i>p</i></sup>, where \e p =
* std::numeric_limits<RealType>::digits, and, if necessary, creating
* additional digits of the number.
*
* @tparam RealType the floating point type to convert to.
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator for generating the necessary digits.
* @return the fraction of the RandomNumber rounded to a RealType.
**********************************************************************/
template<typename RealType, typename Random> RealType Fraction(Random& r) {
STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
"RandomNumber::Fraction: invalid real type RealType");
const int d = std::numeric_limits<RealType>::digits;
const int k = (d + bits - 1)/bits;
const int kg = (d + bits)/bits; // For guard bit
RealType y = 0;
if (Digit(r, kg - 1) & (1U << (kg * bits - d - 1)))
// if guard bit is set, round up.
y += std::pow(RealType(2), -d);
const RealType fact = std::pow(RealType(2), -bits);
RealType mult = RealType(1);
for (int i = 0; i < k; ++i) {
mult *= fact;
y += mult * RealType(i < k - 1 ? RawDigit(i) :
RawDigit(i) & (~0U << (k * bits - d)));
}
return y;
}
/**
* Return the value of the RandomNumber rounded to nearest floating point
* number of type RealType and, if necessary, creating additional digits of
* the number.
*
* @tparam RealType the floating point type to convert to.
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator for generating the necessary digits.
* @return the value of the RandomNumber rounded to a RealType.
**********************************************************************/
template<typename RealType, class Random> RealType Value(Random& r) {
// Ignore the possibility of overflow here (OK because int doesn't
// currently overflow any real type). Assume the real type supports
// denormalized numbers. Need to treat rounding explicitly since the
// missing digits always imply rounding up.
STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
"RandomNumber::Value: invalid real type RealType");
const int digits = std::numeric_limits<RealType>::digits,
min_exp = std::numeric_limits<RealType>::min_exponent;
RealType y;
int lead; // Position of leading bit (0.5 = position 0)
if (_n) lead = highest_bit_idx(_n);
else {
int i = 0;
while ( Digit(r, i) == 0 && i < (-min_exp)/bits ) ++i;
lead = highest_bit_idx(RawDigit(i)) - (i + 1) * bits;
// To handle denormalized numbers set lead = max(lead, min_exp)
lead = lead > min_exp ? lead : min_exp;
}
int trail = lead - digits; // Position of guard bit (0.5 = position 0)
if (trail > 0) {
y = RealType(_n & (~0U << trail));
if (_n & (1U << (trail - 1)))
y += std::pow(RealType(2), trail);
} else {
y = RealType(_n);
int k = (-trail)/bits; // Byte with guard bit
if (Digit(r, k) & (1U << ((k + 1) * bits + trail - 1)))
// If guard bit is set, round bit (some subsequent bit will be 1).
y += std::pow(RealType(2), trail);
// Byte with trailing bit (can be negative)
k = (-trail - 1 + bits)/bits - 1;
const RealType fact = std::pow(RealType(2), -bits);
RealType mult = RealType(1);
for (int i = 0; i <= k; ++i) {
mult *= fact;
y += mult *
RealType(i < k ? RawDigit(i) :
RawDigit(i) & (~0U << ((k + 1) * bits + trail)));
}
}
if (_s < 0) y *= -1;
return y;
}
/**
* Return the range of possible values for the RandomNumber as pair of
* doubles. This doesn't create any additional digits of the result and
* doesn't try to control roundoff.
*
* @return a pair denoting the range with first being the lower limit and
* second being the upper limit.
**********************************************************************/
std::pair<double, double> Range() const throw() {
double y = _n;
const double fact = std::pow(double(2), -bits);
double mult = double(1);
for (unsigned i = 0; i < Size(); ++i) {
mult *= fact;
y += mult * RawDigit(i);
}
return std::pair<double, double>(_s > 0 ? y : -(y + mult),
_s > 0 ? (y + mult) : -y);
}
/**
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return a random digit in [0, 2<sup><i>bits</i></sup>).
**********************************************************************/
template<class Random> static unsigned RandomDigit(Random& r) throw()
{ return unsigned(r.template Integer<bits>()); }
private:
/**
* The integer part
**********************************************************************/
unsigned _n;
/**
* The sign
**********************************************************************/
int _s;
/**
* The fraction part
**********************************************************************/
std::vector<unsigned> _f;
/**
* Fill RandomNumber to \e k digits.
**********************************************************************/
template<class Random> void ExpandTo(Random& r, size_t k) {
size_t l = _f.size();
if (k <= l)
return;
_f.resize(k);
for (size_t i = l; i < k; ++i)
_f[i] = RandomDigit(r);
}
/**
* Return index [0..32] of highest bit set. Return 0 if x = 0, 32 is if x
* = ~0. (From Algorithms for programmers by Joerg Arndt.)
**********************************************************************/
static int highest_bit_idx(unsigned x) throw() {
if (x == 0) return 0;
int r = 1;
if (x & 0xffff0000U) { x >>= 16; r += 16; }
if (x & 0x0000ff00U) { x >>= 8; r += 8; }
if (x & 0x000000f0U) { x >>= 4; r += 4; }
if (x & 0x0000000cU) { x >>= 2; r += 2; }
if (x & 0x00000002U) { r += 1; }
return r;
}
/**
* The number of bits in unsigned.
**********************************************************************/
static const int w = std::numeric_limits<unsigned>::digits;
public:
/**
* A mask for the digits.
**********************************************************************/
static const unsigned mask =
bits == w ? ~0U : ~(~0U << (bits < w ? bits : 0));
};
/**
* \relates RandomNumber
* Print a RandomNumber. Format is n.dddd... where the base for printing is
* 2<sup>max(4,<i>b</i>)</sup>. The ... represents an infinite sequence of
* ungenerated random digits (uniformly distributed). Thus with \e b = 1,
* 0.0... = (0,1/2), 0.00... = (0,1/4), 0.11... = (3/4,1), etc.
**********************************************************************/
template<int bits>
std::ostream& operator<<(std::ostream& os, const RandomNumber<bits>& n) {
const std::ios::fmtflags oldflags = os.flags();
RandomNumber<bits> t = n;
os << (t.Sign() > 0 ? "+" : "-");
unsigned i = t.UInteger();
os << std::hex << std::setfill('0');
if (i == 0)
os << "0";
else {
bool first = true;
const int w = std::numeric_limits<unsigned>::digits;
const unsigned mask = RandomNumber<bits>::mask;
for (int s = ((w + bits - 1)/bits) * bits - bits; s >= 0; s -= bits) {
unsigned d = mask & (i >> s);
if (d || !first) {
if (first) {
os << d;
first = false;
}
else
os << std::setw((bits+3)/4) << d;
}
}
}
os << ".";
unsigned s = t.Size();
for (unsigned i = 0; i < s; ++i)
os << std::setw((bits+3)/4) << t.RawDigit(i);
os << "..." << std::setfill(' ');
os.flags(oldflags);
return os;
}
} // namespace RandomLib
#endif // RANDOMLIB_RANDOMNUMBER_HPP

View File

@ -0,0 +1,77 @@
/**
* \file RandomPower2.hpp
* \brief Header for RandomPower2.
*
* Return and multiply by powers of two.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMPOWER2_HPP)
#define RANDOMLIB_RANDOMPOWER2_HPP 1
#include <cmath> // For std::pow
namespace RandomLib {
/**
* \brief Return or multiply by powers of 2
*
* With some compilers it's fastest to do a table lookup of powers of
* 2. If RANDOMLIB_POWERTABLE is 1, a lookup table is used. If
* RANDOMLIB_POWERTABLE is 0, then std::pow is used.
**********************************************************************/
class RANDOMLIB_EXPORT RandomPower2 {
public:
/**
* Return powers of 2 (either using a lookup table or std::pow)
*
* @param[in] n the integer power.
* @return 2<sup><i>n</i></sup>.
**********************************************************************/
template<typename RealType> static inline RealType pow2(int n) throw() {
#if RANDOMLIB_POWERTABLE
return RealType(power2[n - minpow]);
#else
return std::pow(RealType(2), n);
#endif
}
/**
* Multiply a real by a power of 2
*
* @tparam RealType the type of \e x.
* @param[in] x the real number.
* @param[in] n the power (positive or negative).
* @return \e x 2<sup><i>n</i></sup>.
**********************************************************************/
template<typename RealType>
static inline RealType shiftf(RealType x, int n) throw()
// std::ldexp(x, n); is equivalent, but slower
{ return x * pow2<RealType>(n); }
// Constants
enum {
/**
* Minimum power in RandomPower2::power2
**********************************************************************/
#if RANDOMLIB_LONGDOUBLEPREC > 64
minpow = -120,
#else
minpow = -64,
#endif
maxpow = 64 /**< Maximum power in RandomPower2::power2. */
};
private:
#if RANDOMLIB_POWERTABLE
/**
* Table of powers of two
**********************************************************************/
static const float power2[maxpow - minpow + 1]; // Powers of two
#endif
};
} // namespace RandomLib
#endif // RANDOMLIB_RANDOMPOWER2_HPP

View File

@ -0,0 +1,251 @@
/**
* \file RandomSeed.hpp
* \brief Header for RandomSeed
*
* This provides a base class for random generators.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMSEED_HPP)
#define RANDOMLIB_RANDOMSEED_HPP 1
#include <iostream>
#include <stdexcept>
#include <vector>
#include <iterator>
#include <algorithm> // For std::transform
#include <sstream> // For VectorToString
#include <RandomLib/RandomType.hpp>
#if defined(_MSC_VER)
// Squelch warnings about dll vs vector
#pragma warning (push)
#pragma warning (disable: 4251)
#endif
namespace RandomLib {
/**
* \brief A base class for random generators
*
* This provides facilities for managing the seed and for converting the seed
* into random generator state.
*
* The seed is taken to be a vector of unsigned longs of arbitrary length.
* (Only the low 32 bit of each element of the vector are used.) The class
* provides several methods for setting the seed, static functions for
* producing "random" and "unique" seeds, and facilities for converting the
* seed to a string so that it can be printed easily.
*
* The seeding algorithms are those used by
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
* MT19937</a> with some modifications to make all states accessible and to
* minimize the likelihood of different seeds giving the same state.
*
* Finally some low-level routines are provided to facilitate the creation of
* I/O methods for the random generator.
*
* A random generator class can be written based on this class. The
* generator class would use the base class methods for setting the seed and
* for converting the seed into state. It would provide the machinery for
* advancing the state and for producing random data. It is also responsible
* for the routine to save and restore the generator state (including the
* seed).
*
* Written by Charles Karney <charles@karney.com> and licensed under the
* MIT/X11 License. The seeding algorithms are adapted from those of
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
* MT19937</a>. For more information, see http://randomlib.sourceforge.net/
**********************************************************************/
class RANDOMLIB_EXPORT RandomSeed {
public:
typedef Random_u32 u32;
typedef Random_u64 u64;
virtual ~RandomSeed() throw() = 0;
/**
* A type large enough to hold the seed words. This is needs to hold 32
* bits and is an unsigned long for portability.
**********************************************************************/
typedef RandomType<32, unsigned long> seed_t;
typedef seed_t::type seed_type;
/**
* \name Resetting the seed
**********************************************************************/
///@{
/**
* Set the seed to a vector \e v. Only the low \e 32 bits of each element
* are used.
*
* @tparam IntType the integral type of the elements of the vector.
* @param[in] v the vector of elements.
**********************************************************************/
template<typename IntType> void Reseed(const std::vector<IntType>& v) {
Reseed(v.begin(), v.end());
}
/**
* Set the seed to [\e a, \e b) from a pair of iterators. The iterator
* must produce results which can be converted into seed_type. Only the
* low 32 bits of each element are used.
*
* @tparam InputIterator the type of the iterator.
* @param[in] a the beginning iterator.
* @param[in] b the ending iterator.
**********************************************************************/
template<typename InputIterator>
void Reseed(InputIterator a, InputIterator b) {
// Read new seed into temporary so as not to change object on error.
std::vector<seed_type> t;
std::transform(a, b, back_inserter(t),
seed_t::cast<typename std::iterator_traits<InputIterator>
::value_type>);
_seed.swap(t);
Reset();
}
/**
* Set the seed to [\e n]. Only the low 32 bits of \e n are used.
*
* @param[in] n the new seed to use.
**********************************************************************/
void Reseed(seed_type n) {
// Reserve space for new seed so as not to change object on error.
_seed.reserve(1);
_seed.resize(1);
_seed[0] = seed_t::cast(n);
Reset();
}
/**
* Set the seed to [SeedVector()]. This is the standard way to reseed with
* a "unique" seed.
**********************************************************************/
void Reseed() { Reseed(SeedVector()); }
/**
* Set the seed from the string \e s using Random::StringToVector.
*
* @param[in] s the string to be decoded into a seed.
**********************************************************************/
void Reseed(const std::string& s) {
// Read new seed into temporary so as not to change object on error.
std::vector<seed_type> t = StringToVector(s);
_seed.swap(t);
Reset();
}
///@}
/**
* \name Examining the seed
**********************************************************************/
///@{
/**
* Return reference to the seed vector (read-only).
*
* @return the seed vector.
**********************************************************************/
const std::vector<seed_type>& Seed() const throw() { return _seed; }
/**
* Format the current seed suitable for printing.
*
* @return the seedd as a string.
**********************************************************************/
std::string SeedString() const { return VectorToString(_seed); }
///@}
/**
* \name Resetting the random seed
**********************************************************************/
///@{
/**
* Resets the sequence to its just-seeded state. This needs to be declared
* virtual here so that the Reseed functions can call it after saving the
* seed.
**********************************************************************/
virtual void Reset() throw() = 0;
///@}
/**
* \name Static functions for seed management
**********************************************************************/
///@{
/**
* Return a 32 bits of data suitable for seeding the random generator. The
* result is obtained by combining data from /dev/urandom, gettimeofday,
* time, and getpid to provide a reasonably "random" word of data.
* Usually, it is safer to seed the random generator with SeedVector()
* instead of SeedWord().
*
* @return a single "more-or-less random" seed_type to be used as a seed.
**********************************************************************/
static seed_type SeedWord();
/**
* Return a vector of unsigned longs suitable for seeding the random
* generator. The vector is almost certainly unique; however, the results
* of successive calls to Random::SeedVector() will be correlated. If
* several Random objects are required within a single program execution,
* call Random::SeedVector once, print it out (!), push_back additional
* data to identify the instance (e.g., loop index, thread ID, etc.), and
* use the result to seed the Random object. The number of elements
* included in the vector may depend on the operating system. Additional
* elements may be added in future versions of this library.
*
* @return a "unique" vector of seed_type to be uses as a seed.
**********************************************************************/
static std::vector<seed_type> SeedVector();
/**
* Convert a vector into a string suitable for printing or as an argument
* for Random::Reseed(const std::string& s).
*
* @tparam IntType the integral type of the elements of the vector.
* @param[in] v the vector to be converted.
* @return the resulting string.
**********************************************************************/
template<typename IntType>
static std::string VectorToString(const std::vector<IntType>& v) {
std::ostringstream os;
os << "[";
for (typename std::vector<IntType>::const_iterator n = v.begin();
n != v.end(); ++n) {
if (n != v.begin())
os << ",";
// Normalize in case this is called by user.
os << seed_t::cast(*n);
}
os << "]";
return os.str();
}
/**
* Convert a string into a vector of seed_type suitable for printing or as
* an argument for Random::Reseed(const std::vector<seed_type>& v). Reads
* consecutive digits in string. Thus "[1,2,3]" => [1,2,3]; "-0.123e-4" =>
* [0,123,4], etc. strtoul understands C's notation for octal and
* hexadecimal, for example "012 10 0xa" => [10,10,10]. Reading of a
* number stops at the first illegal character for the base. Thus
* "2006-04-08" => [2006,4,0,8] (i.e., 08 becomes two numbers). Note that
* input numbers greater than ULONG_MAX overflow to ULONG_MAX, which
* probably will result in the number being interpreted as LONG_MASK.
*
* @param[in] s the string to be converted.
* @return the resulting vector of seed_type.
**********************************************************************/
static std::vector<seed_type> StringToVector(const std::string& s);
///@}
protected:
/**
* The seed vector
**********************************************************************/
std::vector<seed_type> _seed;
};
inline RandomSeed::~RandomSeed() throw() {}
} // namespace RandomLib
#if defined(_MSC_VER)
#pragma warning (pop)
#endif
#endif // RANDOMLIB_RANDOMSEED_HPP

View File

@ -0,0 +1,335 @@
/**
* \file RandomSelect.hpp
* \brief Header for RandomSelect.
*
* An implementation of the Walker algorithm for selecting from a finite set.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMSELECT_HPP)
#define RANDOMLIB_RANDOMSELECT_HPP 1
#include <vector>
#include <limits>
#include <stdexcept>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (push)
# pragma warning (disable: 4127)
#endif
namespace RandomLib {
/**
* \brief Random selection from a discrete set.
*
* An implementation of Walker algorithm for selecting from a finite set
* (following Knuth, TAOCP, Vol 2, Sec 3.4.1.A). This provides a rapid way
* of selecting one of several choices depending on a discrete set weights.
* Original citation is\n A. J. Walker,\n An Efficient Method for Generating
* Discrete Random Variables and General Distributions,\n ACM TOMS 3,
* 253--256 (1977).
*
* There are two changes here in the setup algorithm as given by Knuth:
*
* - The probabilities aren't sorted at the beginning of the setup; nor are
* they maintained in a sorted order. Instead they are just partitioned on
* the mean. This improves the setup time from O(\e k<sup>2</sup>) to O(\e
* k).
*
* - The internal calculations are carried out with type \e NumericType. If
* the input weights are of integer type, then choosing an integer type for
* \e NumericType yields an exact solution for the returned distribution
* (assuming that the underlying random generator is exact.)
*
* Example:
* \code
#include <RandomLib/RandomSelect.hpp>
// Weights for throwing a pair of dice
unsigned w[] = { 0, 0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 };
// Initialize selection
RandomLib::RandomSelect<unsigned> sel(w, w + 13);
RandomLib::Random r; // Initialize random numbers
std::cout << "Seed set to " << r.SeedString() << "\n";
std::cout << "Throw a pair of dice 100 times:";
for (unsigned i = 0; i < 100; ++i)
std::cout << " " << sel(r);
std::cout << "\n";
\endcode
*
* @tparam NumericType the numeric type to use (default double).
**********************************************************************/
template<typename NumericType = double> class RandomSelect {
public:
/**
* Initialize in a cleared state (equivalent to having a single
* choice).
**********************************************************************/
RandomSelect() : _k(0), _wsum(0), _wmax(0) {}
/**
* Initialize with a weight vector \e w of elements of type \e WeightType.
* Internal calculations are carried out with type \e NumericType. \e
* NumericType needs to allow Choices() * MaxWeight() to be represented.
* Sensible combinations are:
* - \e WeightType integer, \e NumericType integer with
* digits(\e NumericType) &ge; digits(\e WeightType)
* - \e WeightType integer, \e NumericType real
* - \e WeightType real, \e NumericType real with digits(\e NumericType)
* &ge; digits(\e WeightType)
*
* @tparam WeightType the type of the weights.
* @param[in] w the vector of weights.
* @exception RandomErr if any of the weights are negative or if the total
* weight is not positive.
**********************************************************************/
template<typename WeightType>
RandomSelect(const std::vector<WeightType>& w) { Init(w.begin(), w.end()); }
/**
* Initialize with a weight given by a pair of iterators [\e a, \e b).
*
* @tparam InputIterator the type of the iterator.
* @param[in] a the beginning iterator.
* @param[in] b the ending iterator.
* @exception RandomErr if any of the weights are negative or if the total
* weight is not positive.
**********************************************************************/
template<typename InputIterator>
RandomSelect(InputIterator a, InputIterator b);
/**
* Clear the state (equivalent to having a single choice).
**********************************************************************/
void Init() throw()
{ _k = 0; _wsum = 0; _wmax = 0; _Q.clear(); _Y.clear(); }
/**
* Re-initialize with a weight vector \e w. Leave state unaltered in the
* case of an error.
*
* @tparam WeightType the type of the weights.
* @param[in] w the vector of weights.
**********************************************************************/
template<typename WeightType>
void Init(const std::vector<WeightType>& w) { Init(w.begin(), w.end()); }
/**
* Re-initialize with a weight given as a pair of iterators [\e a, \e b).
* Leave state unaltered in the case of an error.
*
* @tparam InputIterator the type of the iterator.
* @param[in] a the beginning iterator.
* @param[in] b the ending iterator.
**********************************************************************/
template<typename InputIterator>
void Init(InputIterator a, InputIterator b) {
RandomSelect<NumericType> t(a, b);
_Q.reserve(t._k);
_Y.reserve(t._k);
*this = t;
}
/**
* Return an index into the weight vector with probability proportional to
* the weight.
*
* @tparam Random the type of RandomCanonical generator.
* @param[in,out] r the RandomCanonical generator.
* @return the random index into the weight vector.
**********************************************************************/
template<class Random>
unsigned operator()(Random& r) const throw() {
if (_k <= 1)
return 0; // Special cases
const unsigned K = r.template Integer<unsigned>(_k);
// redundant casts to type NumericType to prevent warning from MS Project
return (std::numeric_limits<NumericType>::is_integer ?
r.template Prob<NumericType>(NumericType(_Q[K]),
NumericType(_wsum)) :
r.template Prob<NumericType>(NumericType(_Q[K]))) ?
K : _Y[K];
}
/**
* @return the sum of the weights.
**********************************************************************/
NumericType TotalWeight() const throw() { return _wsum; }
/**
* @return the maximum weight.
**********************************************************************/
NumericType MaxWeight() const throw() { return _wmax; }
/**
* @param[in] i the index in to the weight vector.
* @return the weight for sample \e i. Weight(i) / TotalWeight() gives the
* probability of sample \e i.
**********************************************************************/
NumericType Weight(unsigned i) const throw() {
if (i >= _k)
return NumericType(0);
else if (_k == 1)
return _wsum;
const NumericType n = std::numeric_limits<NumericType>::is_integer ?
_wsum : NumericType(1);
NumericType p = _Q[i];
for (unsigned j = _k; j;)
if (_Y[--j] == i)
p += n - _Q[j];
// If NumericType is integral, then p % _k == 0.
// assert(!std::numeric_limits<NumericType>::is_integer || p % _k == 0);
return (p / NumericType(_k)) * (_wsum / n);
}
/**
* @return the number of choices, i.e., the length of the weight vector.
**********************************************************************/
unsigned Choices() const throw() { return _k; }
private:
/**
* Size of weight vector
**********************************************************************/
unsigned _k;
/**
* Vector of cutoffs
**********************************************************************/
std::vector<NumericType> _Q;
/**
* Vector of aliases
**********************************************************************/
std::vector<unsigned> _Y;
/**
* The sum of the weights
**********************************************************************/
NumericType _wsum;
/**
* The maximum weight
**********************************************************************/
NumericType _wmax;
};
template<typename NumericType> template<typename InputIterator>
RandomSelect<NumericType>::RandomSelect(InputIterator a, InputIterator b) {
typedef typename std::iterator_traits<InputIterator>::value_type
WeightType;
// Disallow WeightType = real, NumericType = integer
STATIC_ASSERT(std::numeric_limits<WeightType>::is_integer ||
!std::numeric_limits<NumericType>::is_integer,
"RandomSelect: inconsistent WeightType and NumericType");
// If WeightType and NumericType are the same type, NumericType as precise
// as WeightType
STATIC_ASSERT(std::numeric_limits<WeightType>::is_integer !=
std::numeric_limits<NumericType>::is_integer ||
std::numeric_limits<NumericType>::digits >=
std::numeric_limits<WeightType>::digits,
"RandomSelect: NumericType insufficiently precise");
_wsum = 0;
_wmax = 0;
std::vector<NumericType> p;
for (InputIterator wptr = a; wptr != b; ++wptr) {
// Test *wptr < 0 without triggering compiler warning when *wptr =
// unsigned
if (!(*wptr > 0 || *wptr == 0))
// This also catches NaNs
throw RandomErr("RandomSelect: Illegal weight");
NumericType w = NumericType(*wptr);
if (w > (std::numeric_limits<NumericType>::max)() - _wsum)
throw RandomErr("RandomSelect: Overflow");
_wsum += w;
_wmax = w > _wmax ? w : _wmax;
p.push_back(w);
}
_k = unsigned(p.size());
if (_wsum <= 0)
throw RandomErr("RandomSelect: Zero total weight");
if (_k <= 1) {
// We treat k <= 1 as a special case in operator()
_Q.clear();
_Y.clear();
return;
}
if ((std::numeric_limits<NumericType>::max)()/NumericType(_k) <
NumericType(_wmax))
throw RandomErr("RandomSelect: Overflow");
std::vector<unsigned> j(_k);
_Q.resize(_k);
_Y.resize(_k);
// Pointers to the next empty low and high slots
unsigned u = 0;
unsigned v = _k - 1;
// Scale input and store in p and setup index array j. Note _wsum =
// mean(p). We could scale out _wsum here, but the following is exact when
// w[i] are low integers.
for (unsigned i = 0; i < _k; ++i) {
p[i] *= NumericType(_k);
j[p[i] > _wsum ? v-- : u++] = i;
}
// Pointers to the next low and high slots to use. Work towards the
// middle. This simplifies the loop exit test to u == v.
u = 0;
v = _k - 1;
// For integer NumericType, store the unnormalized probability in _Q and
// select using the exact Prob(_Q[k], _wsum). For real NumericType, store
// the normalized probability and select using Prob(_Q[k]). There will be
// a round off error in performing the division; but there is also the
// potential for round off errors in performing the arithmetic on p. There
// is therefore no point in simulating the division exactly using the
// slower Prob(real, real).
const NumericType n = std::numeric_limits<NumericType>::is_integer ?
NumericType(1) : _wsum;
while (true) {
// A loop invariant here is mean(p[j[u..v]]) == _wsum
_Q[j[u]] = p[j[u]] / n;
// If all arithmetic were exact this assignment could be:
// if (p[j[u]] < _wsum) _Y[j[u]] = j[v];
// But the following is safer:
_Y[j[u]] = j[p[j[u]] < _wsum ? v : u];
if (u == v) {
// The following assertion may fail because of roundoff errors
// assert( p[j[u]] == _wsum );
break;
}
// Update p, u, and v maintaining the loop invariant
p[j[v]] = p[j[v]] - (_wsum - p[j[u]]);
if (p[j[v]] > _wsum)
++u;
else
j[u] = j[v--];
}
return;
}
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_RANDOMSELECT_HPP

View File

@ -0,0 +1,137 @@
/**
* \file RandomType.hpp
* \brief Class to hold bit-width and unsigned type
*
* This provides a simple class to couple a bit-width and an unsigned type
* capable of holding all the bits. In addition is offers static methods for
* I/O and checksumming.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMTYPE_HPP)
#define RANDOMLIB_RANDOMTYPE_HPP 1
#include <limits>
#include <string>
#include <iostream>
namespace RandomLib {
/**
* \brief Class to hold bit-width and unsigned type
*
* This provides a simple class to couple a bit-width and an unsigned type
* capable of holding all the bits. In addition is offers static methods for
* I/O and checksumming.
*
* @tparam bits the number of significant bits.
* @tparam UIntType the C++ unsigned integer type capable of holding the bits.
**********************************************************************/
template<int bits, typename UIntType>
class RANDOMLIB_EXPORT RandomType {
public:
/**
* The unsigned C++ type
**********************************************************************/
typedef UIntType type;
/**
* The number of significant bits
**********************************************************************/
static const unsigned width = bits;
/**
* A mask for the significant bits.
**********************************************************************/
static const type mask =
~type(0) >> (std::numeric_limits<type>::digits - width);
/**
* The minimum representable value
**********************************************************************/
static const type min = type(0);
/**
* The maximum representable value
**********************************************************************/
static const type max = mask;
/**
* A combined masking and casting operation
*
* @tparam IntType the integer type of the \e x.
* @param[in] x the input integer.
* @return the masked and casted result.
**********************************************************************/
template<typename IntType> static type cast(IntType x) throw()
{ return type(x) & mask; }
/**
* Read a data value from a stream of 32-bit quantities (binary or text)
*
* @param[in,out] is the input stream.
* @param[in] bin true if the stream is binary.
* @param[out] x the data value read from the stream.
**********************************************************************/
static void Read32(std::istream& is, bool bin, type& x);
/**
* Write the data value to a stream of 32-bit quantities (binary or text)
*
* @param[in,out] os the output stream.
* @param[in] bin true if the stream is binary.
* @param[in,out] cnt controls the use of spaces and newlines for text
* output.
* @param[in] x the data value to be written to the stream.
*
* \e cnt should be zero on the first invocation of a series of writes.
* This function increments it by one on each call.
**********************************************************************/
static void Write32(std::ostream& os, bool bin, int& cnt, type x);
/**
* Accumulate a checksum of a integer into a 32-bit check. This implements
* a very simple checksum and is intended to avoid accidental corruption
* only.
*
* @param[in] n the number to be included in the checksum.
* @param[in,out] check the running checksum.
**********************************************************************/
static void CheckSum(type n, uint32_t& check) throw();
};
/**
* The standard unit for 32-bit quantities
**********************************************************************/
typedef RandomType<32, uint32_t> Random_u32;
/**
* The standard unit for 64-bit quantities
**********************************************************************/
typedef RandomType<64, uint64_t> Random_u64;
/**
* The integer type of constructing bitsets. This used to be unsigned long.
* C++11 has made this unsigned long long.
**********************************************************************/
#if defined(_MSC_VER) && _MSC_VER >= 1600
typedef unsigned long long bitset_uint_t;
#else
typedef unsigned long bitset_uint_t;
#endif
/// \cond SKIP
// Accumulate a checksum of a 32-bit quantity into check
template<>
inline void Random_u32::CheckSum(Random_u32::type n, Random_u32::type& check)
throw() {
// Circular shift left by one bit and add new word.
check = (check << 1 | (check >> 31 & Random_u32::type(1))) + n;
check &= Random_u32::mask;
}
// Accumulate a checksum of a 64-bit quantity into check
template<>
inline void Random_u64::CheckSum(Random_u64::type n, Random_u32::type& check)
throw() {
Random_u32::CheckSum(Random_u32::cast(n >> 32), check);
Random_u32::CheckSum(Random_u32::cast(n ), check);
}
/// \endcond
} // namespace RandomLib
#endif // RANDOMLIB_RANDOMTYPE_HPP

View File

@ -0,0 +1,253 @@
/**
* \file UniformInteger.hpp
* \brief Header for UniformInteger
*
* Partially sample a uniform integer distribution.
*
* Copyright (c) Charles Karney (2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_UNIFORMINTEGER_HPP)
#define RANDOMLIB_UNIFORMINTEGER_HPP 1
#include <limits>
namespace RandomLib {
/**
* \brief The partial uniform integer distribution.
*
* A class to sample in [0, \e m). For background, see:
* - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number
* Generation, in "Algorithms and Complexity" (Academic Press, 1976),
* pp. 357--428.
* - J. Lumbroso, Optimal Discrete Uniform Generation from Coin Flips,
* and Applications, http://arxiv.org/abs/1304.1916 (2013)
* .
* Lumbroso's algorithm is a realization of the Knuth-Yao method for the case
* of uniform probabilities. This class generalizes the method to accept
* random digits in a base, \e b = 2<sup>\e bits</sup>. An important
* additional feature is that only sufficient random digits are drawn to
* narrow the allowed range to a power of b. Thus after
* <code>UniformInteger<int,1> u(r,5)</code>, \e u represents \verbatim
range prob
[0,4) 8/15
[0,2) 2/15
[2,4) 2/15
4 1/5 \endverbatim
* <code>u.Min()</code> and <code>u.Max()</code> give the extent of the
* closed range. The number of additional random digits needed to fix the
* value is given by <code>u.Entropy()</code>. The comparison operations may
* require additional digits to be drawn and so the range might be narrowed
* down. If you need a definite value then use <code>u(r)</code>.
*
* The DiscreteNormalAlt class uses UniformInteger to achieve an
* asymptotically ideal scaling wherein the number of random bits required
* per sample is constant + log<sub>2</sub>&sigma;. If Lumbroso's algorithm
* for sampling in [0,\e m) were used the log<sub>2</sub>&sigma; term would
* be multiplied by about 1.4.
*
* It is instructive to look at the Knuth-Yao discrete distribution
* generating (DDG) tree for the case \e m = 5 (the binary expansion of 1/5
* is 0.00110011...); Lumbroso's algorithm implements this tree.
* \image html ky-5.png "Knuth-Yao for \e m = 5"
*
* UniformInteger collapses all of the full subtrees above to their parent
* nodes to yield this tree where now some of the outcomes are ranges.
* \image html ky-5-collapse.png "Collapsed Knuth-Yao for \e m = 5"
*
* Averaging over many samples, the maximum number of digits required to
* construct a UniformInteger, i.e., invoking
* <code>UniformInteger(r,m)</code>, is (2\e b &minus; 1)/(\e b &minus; 1).
* (Note that this does not increase as \e m increases.) The maximum number
* of digits required to sample specific integers, i.e., invoking
* <code>UniformInteger(r,m)(r)</code>, is <i>b</i>/(\e b &minus; 1) +
* log<sub>\e b</sub>\e m. The worst cases are when \e m is slightly more
* than a power of \e b.
*
* The number of random bits required for sampling is shown as a function of
* the fractional part of log<sub>2</sub>\e m below. The red line shows what
* Lumbroso calls the "toll", the number of bits in excess of the entropy
* that are required for sampling.
* \image html
* uniform-bits.png "Random bits to sample in [0,\e m) for \e b = 2"
*
* @tparam IntType the type of the integer (must be signed).
* @tparam bits the number of bits in each digit used for sampling;
* the base for sampling is \e b = 2<sup>\e bits</sup>.
**********************************************************************/
template<typename IntType = int, int bits = 1> class UniformInteger {
public:
/**
* Constructor creating a partially sampled integer in [0, \e m)
*
* @param[in] r random object.
* @param[in] m constructed object represents an integer in [0, \e m).
* @param[in] flip if true, rearrange the ranges so that the widest ones
* are at near the upper end of [0, \e m) (default false).
*
* The samples enough random digits to obtain a uniform range whose size is
* a power of the base. The range can subsequently be narrowed by sampling
* additional digits.
**********************************************************************/
template<class Random>
UniformInteger(Random& r, IntType m, bool flip = false);
/**
* @return the minimum of the current range.
**********************************************************************/
IntType Min() const { return _a; }
/**
* @return the maximum of the current range.
**********************************************************************/
IntType Max() const { return _a + (IntType(1) << (_l * bits)) - 1; }
/**
* @return the entropy of the current range (in units of random digits).
*
* Max() + 1 - Min() = 2<sup>Entropy() * \e bits</sup>.
**********************************************************************/
IntType Entropy() const { return _l; }
/**
* Sample until the entropy vanishes, i.e., Min() = Max().
*
* @return the resulting integer sample.
**********************************************************************/
template<class Random> IntType operator()(Random& r)
{ while (_l) Refine(r); return _a; }
/**
* Negate the range, [Min(), Max()] &rarr; [&minus;Max(), &minus;Min()].
**********************************************************************/
void Negate() { _a = -Max(); }
/**
* Add a constant to the range
*
* @param[in] c the constant to be added.
*
* [Min(), Max()] &rarr; [Min() + \e c, Max() + \e c].
**********************************************************************/
void Add(IntType c) { _a += c; }
/**
* Compare with a fraction, *this &lt; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &lt; <i>p</i>/<i>q</i>.
**********************************************************************/
// test j < p/q (require q > 0)
template<class Random> bool LessThan(Random& r, IntType p, IntType q) {
for (;;) {
if ( (q * Max() < p)) return true;
if (!(q * Min() < p)) return false;
Refine(r);
}
}
/**
* Compare with a fraction, *this &le; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &le; <i>p</i>/<i>q</i>.
**********************************************************************/
template<class Random>
bool LessThanEqual(Random& r, IntType p, IntType q)
{ return LessThan(r, p + 1, q); }
/**
* Compare with a fraction, *this &gt; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &gt; <i>p</i>/<i>q</i>.
**********************************************************************/
template<class Random>
bool GreaterThan(Random& r, IntType p, IntType q)
{ return !LessThanEqual(r, p, q); }
/**
* Compare with a fraction, *this &ge; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &ge; <i>p</i>/<i>q</i>.
**********************************************************************/
template<class Random>
bool GreaterThanEqual(Random& r, IntType p, IntType q)
{ return !LessThan(r, p, q); }
/**
* Check that overflow will not happen.
*
* @param[in] mmax the largest \e m in the constructor.
* @param[in] qmax the largest \e q in LessThan().
* @return true if overflow will not happen.
*
* It is important that this check be carried out. If overflow occurs,
* incorrect results are obtained and the constructor may never terminate.
**********************************************************************/
static bool Check(IntType mmax, IntType qmax) {
return ( mmax - 1 <= ((std::numeric_limits<IntType>::max)() >> bits) &&
mmax - 1 <= (std::numeric_limits<IntType>::max)() / qmax );
}
private:
IntType _a, _l; // current range is _a + [0, 2^(bits*_l)).
template<class Random> static unsigned RandomDigit(Random& r) throw()
{ return unsigned(r.template Integer<bits>()); }
template<class Random> void Refine(Random& r) // only gets called if _l > 0.
{ _a += IntType(RandomDigit(r) << (bits * --_l)); }
};
template<typename IntType, int bits> template<class Random>
UniformInteger<IntType, bits>::UniformInteger(Random& r, IntType m, bool flip)
{
STATIC_ASSERT(std::numeric_limits<IntType>::is_integer,
"UniformInteger: invalid integer type IntType");
STATIC_ASSERT(std::numeric_limits<IntType>::is_signed,
"UniformInteger: IntType must be a signed type");
STATIC_ASSERT(bits > 0 && bits < std::numeric_limits<IntType>::digits &&
bits <= std::numeric_limits<unsigned>::digits,
"UniformInteger: bits out of range");
m = m < 1 ? 1 : m;
for (IntType v = 1, c = 0;;) {
_l = 0; _a = c;
for (IntType w = v, a = c, d = 1;;) {
// play out Lumbroso's algorithm without drawing random digits with w
// playing the role of v and c represented by the range [a, a + d).
// Return if both ends of range qualify as return values at the same
// time. Otherwise, fail and draw another random digit.
if (w >= m) {
IntType j = (a / m) * m; a -= j; w -= j;
if (w >= m) {
if (a + d <= m) { _a = !flip ? a : m - a - d; return; }
break;
}
}
w <<= bits; a <<= bits; d <<= bits; ++_l;
}
IntType j = (v / m) * m; v -= j; c -= j;
v <<= bits; c <<= bits; c += IntType(RandomDigit(r));
}
}
/**
* \relates UniformInteger
* Print a UniformInteger. Format is [\e min,\e max] unless the entropy is
* zero, in which case it's \e val.
**********************************************************************/
template<typename IntType, int bits>
std::ostream& operator<<(std::ostream& os,
const UniformInteger<IntType, bits>& u) {
if (u.Entropy())
os << "[" << u.Min() << "," << u.Max() << "]";
else
os << u.Min();
return os;
}
} // namespace RandomLib
#endif // RANDOMLIB_UNIFORMINTEGER_HPP

View File

@ -50,21 +50,15 @@
-# Define the appropriate symbol for the converter you wish to use and
include the SimpleIni.h header file. If no specific converter is defined
then the default converter is used. The default conversion mode uses
SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other
platforms. If you are using ICU then SI_CONVERT_ICU is supported on all
SI_CONVERT_WIN32 on Windows and SI_CONVERT_ICU on all other
platforms.
-# Declare an instance the appropriate class. Note that the following
definitions are just shortcuts for commonly used types. Other types
(PRUnichar, unsigned short, unsigned char) are also possible.
<table>
<tr><th>Interface <th>Case-sensitive <th>Load UTF-8 <th>Load MBCS <th>Typedef
<tr><th>SI_CONVERT_GENERIC
<tr><td>char <td>No <td>Yes <td>Yes #1 <td>CSimpleIniA
<tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
<tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
<tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
<tr><th>SI_CONVERT_WIN32
<tr><td>char <td>No <td>No #2 <td>Yes <td>CSimpleIniA
<tr><td>char <td>No <td>No #1 <td>Yes <td>CSimpleIniA
<tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
<tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
<tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
@ -74,8 +68,7 @@
<tr><td>UChar <td>No <td>Yes <td>Yes <td>CSimpleIniW
<tr><td>UChar <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
</table>
#1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.<br>
#2 Only affects Windows. On Windows this uses MBCS functions and
#1 Only affects Windows. On Windows this uses MBCS functions and
so may fold case incorrectly leading to uncertain results.
-# Call LoadData() or LoadFile() to load and parse the INI configuration file
-# Access and modify the data of the file using the following functions
@ -149,12 +142,11 @@
@section notes NOTES
- To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
- When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
Unicode, or SI_CONVERT_ICU.
- When using SI_CONVERT_ICU, ICU header files must be on the include
path and icuuc.lib must be linked in.
- To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
you should use SI_CONVERT_GENERIC.
you should use SI_CONVERT_ICU.
- The collation (sorting) order used for sections and keys returned from
iterators is NOT DEFINED. If collation order of the text is important
then it should be done yourself by either supplying a replacement
@ -164,7 +156,7 @@
- Not thread-safe so manage your own locking
@section contrib CONTRIBUTIONS
- 2010/05/03: Tobias Gehrig: added GetDoubleValue()
@section licence MIT LICENCE
@ -321,12 +313,6 @@ public:
return *this;
}
#if defined(_MSC_VER) && _MSC_VER <= 1200
/** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */
bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); }
bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); }
#endif
/** Strict less ordering by name of key only */
struct KeyOrder : std::binary_function<Entry, Entry, bool> {
bool operator()(const Entry & lhs, const Entry & rhs) const {
@ -344,6 +330,16 @@ public:
return KeyOrder()(lhs.pItem, rhs.pItem);
}
};
/** Like LoadOrder, but empty name always goes first */
struct LoadOrderEmptyFirst : std::binary_function<Entry, Entry, bool> {
bool operator()(const Entry & lhs, const Entry & rhs) const {
if (*lhs.pItem == 0 || *rhs.pItem == 0) {
return *lhs.pItem < *rhs.pItem;
}
return LoadOrder()(lhs, rhs);
}
};
};
/** map keys to values */
@ -530,7 +526,7 @@ public:
bool IsMultiLine() const { return m_bAllowMultiLine; }
/** Should spaces be added around the equals sign when writing key/value
pairs out. When true, the result will be "key = value". When false,
pairs out. When true, the result will be "key = value". When false,
the result will be "key=value". This value may be changed at any time.
\param a_bSpaces Add spaces around the equals sign?
@ -541,7 +537,7 @@ public:
/** Query the status of spaces output */
bool UsingSpaces() const { return m_bSpaces; }
/*-----------------------------------------------------------------------*/
/** @}
@{ @name Loading INI Data */
@ -771,8 +767,8 @@ public:
) const;
/** Retrieve all unique key names in a section. The sort order of the
returned strings is NOT DEFINED. You can sort the names into the load
order if desired. Search this file for ".sort" for an example. Only
returned strings is NOT DEFINED. You can sort the names into the load
order if desired. Search this file for ".sort" for an example. Only
unique key names are returned.
NOTE! This structure contains only pointers to strings. The actual
@ -793,8 +789,8 @@ public:
) const;
/** Retrieve all values for a specific key. This method can be used when
multiple keys are both enabled and disabled. Note that the sort order
of the returned strings is NOT DEFINED. You can sort the names into
multiple keys are both enabled and disabled. Note that the sort order
of the returned strings is NOT DEFINED. You can sort the names into
the load order if desired. Search this file for ".sort" for an example.
NOTE! The returned values are pointers to string data stored in memory
@ -915,7 +911,7 @@ public:
Strings starting with "t", "y", "on" or "1" are returned as logically true.
Strings starting with "f", "n", "of" or "0" are returned as logically false.
For all other values the default is returned. Character comparisons are
For all other values the default is returned. Character comparisons are
case-insensitive.
@param a_pSection Section to search
@ -954,9 +950,9 @@ public:
character starting every line).
@param a_bForceReplace Should all existing values in a multi-key INI
file be replaced with this entry. This option has
no effect if not using multi-key files. The
no effect if not using multi-key files. The
difference between Delete/SetValue and SetValue
with a_bForceReplace = true, is that the load
with a_bForceReplace = true, is that the load
order and comment will be preserved this way.
@return SI_Error See error definitions
@ -978,19 +974,19 @@ public:
when multiple keys are enabled.
@param a_pSection Section to add or update
@param a_pKey Key to add or update.
@param a_nValue Value to set.
@param a_pComment Comment to be associated with the key. See the
@param a_pKey Key to add or update.
@param a_nValue Value to set.
@param a_pComment Comment to be associated with the key. See the
notes on SetValue() for comments.
@param a_bUseHex By default the value will be written to the file
in decimal format. Set this to true to write it
@param a_bUseHex By default the value will be written to the file
in decimal format. Set this to true to write it
as hexadecimal.
@param a_bForceReplace Should all existing values in a multi-key INI
file be replaced with this entry. This option has
no effect if not using multi-key files. The
difference between Delete/SetLongValue and
SetLongValue with a_bForceReplace = true, is that
the load order and comment will be preserved this
no effect if not using multi-key files. The
difference between Delete/SetLongValue and
SetLongValue with a_bForceReplace = true, is that
the load order and comment will be preserved this
way.
@return SI_Error See error definitions
@ -1010,16 +1006,16 @@ public:
when multiple keys are enabled.
@param a_pSection Section to add or update
@param a_pKey Key to add or update.
@param a_nValue Value to set.
@param a_pComment Comment to be associated with the key. See the
@param a_pKey Key to add or update.
@param a_nValue Value to set.
@param a_pComment Comment to be associated with the key. See the
notes on SetValue() for comments.
@param a_bForceReplace Should all existing values in a multi-key INI
file be replaced with this entry. This option has
no effect if not using multi-key files. The
difference between Delete/SetDoubleValue and
SetDoubleValue with a_bForceReplace = true, is that
the load order and comment will be preserved this
no effect if not using multi-key files. The
difference between Delete/SetDoubleValue and
SetDoubleValue with a_bForceReplace = true, is that
the load order and comment will be preserved this
way.
@return SI_Error See error definitions
@ -1038,16 +1034,16 @@ public:
when multiple keys are enabled.
@param a_pSection Section to add or update
@param a_pKey Key to add or update.
@param a_bValue Value to set.
@param a_pComment Comment to be associated with the key. See the
@param a_pKey Key to add or update.
@param a_bValue Value to set.
@param a_pComment Comment to be associated with the key. See the
notes on SetValue() for comments.
@param a_bForceReplace Should all existing values in a multi-key INI
file be replaced with this entry. This option has
no effect if not using multi-key files. The
difference between Delete/SetBoolValue and
SetBoolValue with a_bForceReplace = true, is that
the load order and comment will be preserved this
no effect if not using multi-key files. The
difference between Delete/SetBoolValue and
SetBoolValue with a_bForceReplace = true, is that
the load order and comment will be preserved this
way.
@return SI_Error See error definitions
@ -1168,9 +1164,9 @@ private:
comment character starting every line).
@param a_bForceReplace Should all existing values in a multi-key INI
file be replaced with this entry. This option has
no effect if not using multi-key files. The
no effect if not using multi-key files. The
difference between Delete/AddEntry and AddEntry
with a_bForceReplace = true, is that the load
with a_bForceReplace = true, is that the load
order and comment will be preserved this way.
@param a_bCopyStrings Should copies of the strings be made or not.
If false then the pointers will be used as is.
@ -1265,7 +1261,7 @@ private:
/** Should spaces be written out surrounding the equals sign? */
bool m_bSpaces;
/** Next order value, used to ensure sections and keys are output in the
same order that they are loaded/added.
*/
@ -1385,14 +1381,14 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
if (lSize == 0) {
return SI_OK;
}
// allocate and ensure NULL terminated
char * pData = new char[lSize+1];
if (!pData) {
return SI_NOMEM;
}
pData[lSize] = 0;
// load data into buffer
fseek(a_fpFile, 0, SEEK_SET);
size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile);
@ -2045,15 +2041,15 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetLongValue(
}
// any invalid strings will return the default value
if (*pszSuffix) {
return a_nDefault;
if (*pszSuffix) {
return a_nDefault;
}
return nValue;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetLongValue(
const SI_CHAR * a_pSection,
const SI_CHAR * a_pKey,
@ -2077,7 +2073,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetLongValue(
// convert to output text
SI_CHAR szOutput[64];
SI_CONVERTER c(m_bStoreIsUtf8);
c.ConvertFromStore(szInput, strlen(szInput) + 1,
c.ConvertFromStore(szInput, strlen(szInput) + 1,
szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
// actually add it
@ -2108,15 +2104,15 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetDoubleValue(
double nValue = strtod(szValue, &pszSuffix);
// any invalid strings will return the default value
if (!pszSuffix || *pszSuffix) {
return a_nDefault;
if (!pszSuffix || *pszSuffix) {
return a_nDefault;
}
return nValue;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetDoubleValue(
const SI_CHAR * a_pSection,
const SI_CHAR * a_pKey,
@ -2139,7 +2135,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetDoubleValue(
// convert to output text
SI_CHAR szOutput[64];
SI_CONVERTER c(m_bStoreIsUtf8);
c.ConvertFromStore(szInput, strlen(szInput) + 1,
c.ConvertFromStore(szInput, strlen(szInput) + 1,
szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
// actually add it
@ -2182,7 +2178,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetBoolValue(
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetBoolValue(
const SI_CHAR * a_pSection,
const SI_CHAR * a_pKey,
@ -2200,13 +2196,13 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetBoolValue(
// convert to output text
SI_CHAR szOutput[64];
SI_CONVERTER c(m_bStoreIsUtf8);
c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
// actually add it
return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
bool
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllValues(
@ -2407,15 +2403,13 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
a_oOutput.Write(SI_UTF8_SIGNATURE);
}
// get all of the sections sorted in load order
// get all of the sections sorted in load order with root section first
TNamesDepend oSections;
GetAllSections(oSections);
#if defined(_MSC_VER) && _MSC_VER <= 1200
oSections.sort();
#elif defined(__BORLANDC__)
oSections.sort(Entry::LoadOrder());
#if defined(__BORLANDC__)
oSections.sort(Entry::LoadOrderEmptyFirst());
#else
oSections.sort(typename Entry::LoadOrder());
oSections.sort(typename Entry::LoadOrderEmptyFirst());
#endif
// write the file comment if we have one
@ -2462,9 +2456,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
// get all of the keys sorted in load order
TNamesDepend oKeys;
GetAllKeys(iSection->pItem, oKeys);
#if defined(_MSC_VER) && _MSC_VER <= 1200
oKeys.sort();
#elif defined(__BORLANDC__)
#if defined(__BORLANDC__)
oKeys.sort(Entry::LoadOrder());
#else
oKeys.sort(typename Entry::LoadOrder());
@ -2662,17 +2654,15 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::DeleteString(
// SimpleIni.h, set the converter that you wish you use by defining one of the
// following symbols.
//
// SI_CONVERT_GENERIC Use the Unicode reference conversion library in
// the accompanying files ConvertUTF.h/c
// SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
// ICU headers on include path and icuuc.lib
// SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
#if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
#if !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
# ifdef _WIN32
# define SI_CONVERT_WIN32
# else
# define SI_CONVERT_GENERIC
# define SI_CONVERT_ICU
# endif
#endif
@ -2835,214 +2825,6 @@ public:
};
// ---------------------------------------------------------------------------
// SI_CONVERT_GENERIC
// ---------------------------------------------------------------------------
#ifdef SI_CONVERT_GENERIC
#define SI_Case SI_GenericCase
#define SI_NoCase SI_GenericNoCase
#include <wchar.h>
#include "ConvertUTF.h"
/**
* Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference
* library functions. This can be used on all platforms.
*/
template<class SI_CHAR>
class SI_ConvertW {
bool m_bStoreIsUtf8;
protected:
SI_ConvertW() { }
public:
SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
/* copy and assignment */
SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
SI_ConvertW & operator=(const SI_ConvertW & rhs) {
m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
return *this;
}
/** Calculate the number of SI_CHAR required for converting the input
* from the storage format. The storage format is always UTF-8 or MBCS.
*
* @param a_pInputData Data in storage format to be converted to SI_CHAR.
* @param a_uInputDataLen Length of storage format data in bytes. This
* must be the actual length of the data, including
* NULL byte if NULL terminated string is required.
* @return Number of SI_CHAR required by the string when
* converted. If there are embedded NULL bytes in the
* input data, only the string up and not including
* the NULL byte will be converted.
* @return -1 cast to size_t on a conversion error.
*/
size_t SizeFromStore(
const char * a_pInputData,
size_t a_uInputDataLen)
{
SI_ASSERT(a_uInputDataLen != (size_t) -1);
if (m_bStoreIsUtf8) {
// worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t
// so we just return the same number of characters required as for
// the source text.
return a_uInputDataLen;
}
#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))
// fall back processing for platforms that don't support a NULL dest to mbstowcs
// worst case scenario is 1:1, this will be a sufficient buffer size
(void)a_pInputData;
return a_uInputDataLen;
#else
// get the actual required buffer size
return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
#endif
}
/** Convert the input string from the storage format to SI_CHAR.
* The storage format is always UTF-8 or MBCS.
*
* @param a_pInputData Data in storage format to be converted to SI_CHAR.
* @param a_uInputDataLen Length of storage format data in bytes. This
* must be the actual length of the data, including
* NULL byte if NULL terminated string is required.
* @param a_pOutputData Pointer to the output buffer to received the
* converted data.
* @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
* @return true if all of the input data was successfully
* converted.
*/
bool ConvertFromStore(
const char * a_pInputData,
size_t a_uInputDataLen,
SI_CHAR * a_pOutputData,
size_t a_uOutputDataSize)
{
if (m_bStoreIsUtf8) {
// This uses the Unicode reference implementation to do the
// conversion from UTF-8 to wchar_t. The required files are
// ConvertUTF.h and ConvertUTF.c which should be included in
// the distribution but are publically available from unicode.org
// at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
ConversionResult retval;
const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
if (sizeof(wchar_t) == sizeof(UTF32)) {
UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
retval = ConvertUTF8toUTF32(
&pUtf8, pUtf8 + a_uInputDataLen,
&pUtf32, pUtf32 + a_uOutputDataSize,
lenientConversion);
}
else if (sizeof(wchar_t) == sizeof(UTF16)) {
UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
retval = ConvertUTF8toUTF16(
&pUtf8, pUtf8 + a_uInputDataLen,
&pUtf16, pUtf16 + a_uOutputDataSize,
lenientConversion);
}
return retval == conversionOK;
}
// convert to wchar_t
size_t retval = mbstowcs(a_pOutputData,
a_pInputData, a_uOutputDataSize);
return retval != (size_t)(-1);
}
/** Calculate the number of char required by the storage format of this
* data. The storage format is always UTF-8 or MBCS.
*
* @param a_pInputData NULL terminated string to calculate the number of
* bytes required to be converted to storage format.
* @return Number of bytes required by the string when
* converted to storage format. This size always
* includes space for the terminating NULL character.
* @return -1 cast to size_t on a conversion error.
*/
size_t SizeToStore(
const SI_CHAR * a_pInputData)
{
if (m_bStoreIsUtf8) {
// worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char
size_t uLen = 0;
while (a_pInputData[uLen]) {
++uLen;
}
return (6 * uLen) + 1;
}
else {
size_t uLen = wcstombs(NULL, a_pInputData, 0);
if (uLen == (size_t)(-1)) {
return uLen;
}
return uLen + 1; // include NULL terminator
}
}
/** Convert the input string to the storage format of this data.
* The storage format is always UTF-8 or MBCS.
*
* @param a_pInputData NULL terminated source string to convert. All of
* the data will be converted including the
* terminating NULL character.
* @param a_pOutputData Pointer to the buffer to receive the converted
* string.
* @param a_uOutputDataSize Size of the output buffer in char.
* @return true if all of the input data, including the
* terminating NULL character was successfully
* converted.
*/
bool ConvertToStore(
const SI_CHAR * a_pInputData,
char * a_pOutputData,
size_t a_uOutputDataSize
)
{
if (m_bStoreIsUtf8) {
// calc input string length (SI_CHAR type and size independent)
size_t uInputLen = 0;
while (a_pInputData[uInputLen]) {
++uInputLen;
}
++uInputLen; // include the NULL char
// This uses the Unicode reference implementation to do the
// conversion from wchar_t to UTF-8. The required files are
// ConvertUTF.h and ConvertUTF.c which should be included in
// the distribution but are publically available from unicode.org
// at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
ConversionResult retval;
UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
if (sizeof(wchar_t) == sizeof(UTF32)) {
const UTF32 * pUtf32 = (const UTF32 *) a_pInputData;
retval = ConvertUTF32toUTF8(
&pUtf32, pUtf32 + uInputLen,
&pUtf8, pUtf8 + a_uOutputDataSize,
lenientConversion);
}
else if (sizeof(wchar_t) == sizeof(UTF16)) {
const UTF16 * pUtf16 = (const UTF16 *) a_pInputData;
retval = ConvertUTF16toUTF8(
&pUtf16, pUtf16 + uInputLen,
&pUtf8, pUtf8 + a_uOutputDataSize,
lenientConversion);
}
return retval == conversionOK;
}
else {
size_t retval = wcstombs(a_pOutputData,
a_pInputData, a_uOutputDataSize);
return retval != (size_t) -1;
}
}
};
#endif // SI_CONVERT_GENERIC
// ---------------------------------------------------------------------------
// SI_CONVERT_ICU
// ---------------------------------------------------------------------------
@ -3245,7 +3027,13 @@ public:
# endif
#endif
#ifdef NOMINMAX
#include <windows.h>
#else
#define NOMINMAX
#include <windows.h>
#undef NOMINMAX
#endif
#ifdef SI_NO_MBCS
# define SI_NoCase SI_GenericNoCase
#else // !SI_NO_MBCS

File diff suppressed because it is too large Load Diff

View File

@ -1,235 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#ifndef INCLUDE_IRC_ERRORS_H
#define INCLUDE_IRC_ERRORS_H
#ifndef IN_INCLUDE_LIBIRC_H
#error This file should not be included directly, include just libircclient.h
#endif
/*! brief No error
* \ingroup errorcodes
*/
#define LIBIRC_ERR_OK 0
/*! \brief Invalid argument
*
* An invalid value was given for one of the arguments to a function.
* For example, supplying the NULL value for \a channel argument of
* irc_cmd_join() produces LIBIRC_ERR_INVAL error. You should fix the code.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_INVAL 1
/*! \brief Could not resolve host.
*
* The host name supplied for irc_connect() function could not be resolved
* into valid IP address. Usually means that host name is invalid.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_RESOLV 2
/*! \brief Could not create socket.
*
* The new socket could not be created or made non-blocking. Usually means
* that the server is out of resources, or (rarely :) a bug in libircclient.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_SOCKET 3
/*! \brief Could not connect.
*
* The socket could not connect to the IRC server, or to the destination DCC
* part. Usually means that either the IRC server is down or its address is
* invalid. For DCC the reason usually is the firewall on your or destination
* computer, which refuses DCC transfer.
*
* \sa irc_run irc_connect
* \ingroup errorcodes
*/
#define LIBIRC_ERR_CONNECT 4
/*! \brief Connection closed by remote peer.
*
* The IRC connection was closed by the IRC server (which could mean that an
* IRC operator just have banned you from the server :)), or the DCC connection
* was closed by remote peer - for example, the other side just quits his mIrc.
* Usually it is not an error.
*
* \sa irc_run irc_connect irc_dcc_callback_t
* \ingroup errorcodes
*/
#define LIBIRC_ERR_CLOSED 5
/*! \brief Out of memory
*
* There are two possible reasons for this error. First is that memory could
* not be allocated for libircclient use, and this error usually is fatal.
* Second reason is that the command queue (which keeps command ready to be
* sent to the IRC server) is full, and could not accept more commands yet.
* In this case you should just wait, and repeat the command later.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_NOMEM 6
/*! \brief Could not accept new connection
*
* A DCC chat/send connection from the remote peer could not be accepted.
* Either the connection was just terminated before it is accepted, or there
* is a bug in libircclient.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_ACCEPT 7
/*! \brief Could not send this
*
* A \a filename supplied to irc_dcc_sendfile() could not be sent. Either is
* is not a file (a directory or a socket, for example), or it is not readable. *
*
* \sa LIBIRC_ERR_OPENFILE
* \ingroup errorcodes
*/
#define LIBIRC_ERR_NODCCSEND 9
/*! \brief Could not read DCC file or socket
*
* Either a DCC file could not be read (for example, was truncated during
* sending), or a DCC socket returns a read error, which usually means that
* the network connection is terminated.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_READ 10
/*! \brief Could not write DCC file or socket
*
* Either a DCC file could not be written (for example, there is no free space
* on disk), or a DCC socket returns a write error, which usually means that
* the network connection is terminated.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_WRITE 11
/*! \brief Invalid state
*
* The function is called when it is not allowed to be called. For example,
* irc_cmd_join() was called before the connection to IRC server succeed, and
* ::event_connect is called.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_STATE 12
/*! \brief Operation timed out
*
* The DCC request is timed out.
* There is a timer for each DCC request, which tracks connecting, accepting
* and non-accepted/declined DCC requests. For every request this timer
* is currently 60 seconds. If the DCC request was not connected, accepted
* or declined during this time, it will be terminated with this error.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_TIMEOUT 13
/*! \brief Could not open file for DCC send
*
* The file specified in irc_dcc_sendfile() could not be opened.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_OPENFILE 14
/*! \brief IRC server connection terminated
*
* The connection to the IRC server was terminated - possibly, by network
* error. Try to irc_connect() again.
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_TERMINATED 15
/*! \brief IPv6 not supported
*
* The function which requires IPv6 support was called, but the IPv6 support was not compiled
* into the application
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_NOIPV6 16
/*! \brief SSL not supported
*
* The SSL connection was required but the library was not compiled with SSL support
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_SSL_NOT_SUPPORTED 17
/*! \brief SSL initialization failed
*
* The SSL connection was required but the library was not compiled with SSL support
*
* \ingroup errorcodes
*/
#define LIBIRC_ERR_SSL_INIT_FAILED 18
/*! \brief SSL connection failed
*
* SSL handshare failed when attempting to connect to the server. Typically this means you're trying
* to use SSL but attempting to connect to a non-SSL port.
* \ingroup errorcodes
*/
#define LIBIRC_ERR_CONNECT_SSL_FAILED 19
/*! \brief SSL certificate verify failed
*
* The server is using the self-signed certificate. Use LIBIRC_OPTION_SSL_NO_VERIFY option to connect to it.
* \ingroup errorcodes
*/
#define LIBIRC_ERR_SSL_CERT_VERIFY_FAILED 20
// Internal max error value count.
// If you added more errors, add them to errors.c too!
#define LIBIRC_ERR_MAX 21
#endif /* INCLUDE_IRC_ERRORS_H */

View File

@ -1,389 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#ifndef INCLUDE_IRC_EVENTS_H
#define INCLUDE_IRC_EVENTS_H
#ifndef IN_INCLUDE_LIBIRC_H
#error This file should not be included directly, include just libircclient.h
#endif
/*!
* \fn typedef void (*irc_event_callback_t) (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
* \brief A most common event callback
*
* \param session the session, which generates an event
* \param event the text name of the event. Useful in case you use a single
* event handler for several events simultaneously.
* \param origin the originator of the event. See the note below.
* \param params a list of event params. Depending on the event nature, it
* could have zero or more params. The actual number of params
* is specified in count. None of the params can be NULL, but
* 'params' pointer itself could be NULL for some events.
* \param count the total number of params supplied.
*
* Every event generates a callback. This callback is generated by most events.
* Depending on the event nature, it can provide zero or more params. For each
* event, the number of provided params is fixed, and their meaning is
* described.
*
* Every event has origin, though the \a origin variable may be NULL, which
* means that event origin is unknown. The origin usually looks like
* nick!host\@ircserver, i.e. like tim!home\@irc.krasnogorsk.ru. Such origins
* can not be used in IRC commands, and need to be stripped (i.e. host and
* server part should be cut off) before using. This can be done either
* explicitly, by calling irc_target_get_nick(), or implicitly for all the
* events - by setting the #LIBIRC_OPTION_STRIPNICKS option with irc_option_set().
*
* \ingroup events
*/
typedef void (*irc_event_callback_t) (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count);
/*!
* \fn typedef void (*irc_eventcode_callback_t) (irc_session_t * session, unsigned int event, const char * origin, const char ** params, unsigned int count)
* \brief A numeric event callback
*
* \param session the session, which generates an event
* \param event the numeric code of the event. Useful in case you use a
* single event handler for several events simultaneously.
* \param origin the originator of the event. See the note below.
* \param params a list of event params. Depending on the event nature, it
* could have zero or more params. The actual number of params
* is specified in count. None of the params can be NULL, but
* 'params' pointer itself could be NULL for some events.
* \param count the total number of params supplied.
*
* Most times in reply to your actions the IRC server generates numeric
* callbacks. Most of them are error codes, and some of them mark list start
* and list stop markers. Every code has its own set of params; for details
* you can either experiment, or read RFC 1459.
*
* Every event has origin, though the \a origin variable may be NULL, which
* means that event origin is unknown. The origin usually looks like
* nick!host\@ircserver, i.e. like tim!home\@irc.krasnogorsk.ru. Such origins
* can not be used in IRC commands, and need to be stripped (i.e. host and
* server part should be cut off) before using. This can be done either
* explicitly, by calling irc_target_get_nick(), or implicitly for all the
* events - by setting the #LIBIRC_OPTION_STRIPNICKS option with irc_option_set().
*
* \ingroup events
*/
typedef void (*irc_eventcode_callback_t) (irc_session_t * session, unsigned int event, const char * origin, const char ** params, unsigned int count);
/*!
* \fn typedef void (*irc_event_dcc_chat_t) (irc_session_t * session, const char * nick, const char * addr, irc_dcc_t dccid)
* \brief A remote DCC CHAT request callback
*
* \param session the session, which generates an event
* \param nick the person who requested DCC CHAT with you.
* \param addr the person's IP address in decimal-dot notation.
* \param dccid an id associated with this request. Use it in calls to
* irc_dcc_accept() or irc_dcc_decline().
*
* This callback is called when someone requests DCC CHAT with you. In respond
* you should call either irc_dcc_accept() to accept chat request, or
* irc_dcc_decline() to decline chat request.
*
* \sa irc_dcc_accept or irc_dcc_decline
* \ingroup events
*/
typedef void (*irc_event_dcc_chat_t) (irc_session_t * session, const char * nick, const char * addr, irc_dcc_t dccid);
/*!
* \fn typedef void (*irc_event_dcc_send_t) (irc_session_t * session, const char * nick, const char * addr, const char * filename, unsigned long size, irc_dcc_t dccid)
* \brief A remote DCC CHAT request callback
*
* \param session the session, which generates an event
* \param nick the person who requested DCC CHAT with you.
* \param addr the person's IP address in decimal-dot notation.
* \param filename the sent filename.
* \param size the filename size.
* \param dccid an id associated with this request. Use it in calls to
* irc_dcc_accept() or irc_dcc_decline().
*
* This callback is called when someone wants to send a file to you using
* DCC SEND. As with chat, in respond you should call either irc_dcc_accept()
* to accept this request and receive the file, or irc_dcc_decline() to
* decline this request.
*
* \sa irc_dcc_accept or irc_dcc_decline
* \ingroup events
*/
typedef void (*irc_event_dcc_send_t) (irc_session_t * session, const char * nick, const char * addr, const char * filename, unsigned long size, irc_dcc_t dccid);
/*! \brief Event callbacks structure.
*
* All the communication with the IRC network is based on events. Generally
* speaking, event is anything generated by someone else in the network,
* or by the IRC server itself. "Someone sends you a message", "Someone
* has joined the channel", "Someone has quits IRC" - all these messages
* are events.
*
* Every event has its own event handler, which is called when the
* appropriate event is received. You don't have to define all the event
* handlers; define only the handlers for the events you need to intercept.
*
* Most event callbacks are the types of ::irc_event_callback_t. There are
* also events, which generate ::irc_eventcode_callback_t,
* ::irc_event_dcc_chat_t and ::irc_event_dcc_send_t callbacks.
*
* \ingroup events
*/
typedef struct
{
/*!
* The "on_connect" event is triggered when the client successfully
* connects to the server, and could send commands to the server.
* No extra params supplied; \a params is 0.
*/
irc_event_callback_t event_connect;
/*!
* The "nick" event is triggered when the client receives a NICK message,
* meaning that someone (including you) on a channel with the client has
* changed their nickname.
*
* \param origin the person, who changes the nick. Note that it can be you!
* \param params[0] mandatory, contains the new nick.
*/
irc_event_callback_t event_nick;
/*!
* The "quit" event is triggered upon receipt of a QUIT message, which
* means that someone on a channel with the client has disconnected.
*
* \param origin the person, who is disconnected
* \param params[0] optional, contains the reason message (user-specified).
*/
irc_event_callback_t event_quit;
/*!
* The "join" event is triggered upon receipt of a JOIN message, which
* means that someone has entered a channel that the client is on.
*
* \param origin the person, who joins the channel. By comparing it with
* your own nickname, you can check whether your JOIN
* command succeed.
* \param params[0] mandatory, contains the channel name.
*/
irc_event_callback_t event_join;
/*!
* The "part" event is triggered upon receipt of a PART message, which
* means that someone has left a channel that the client is on.
*
* \param origin the person, who leaves the channel. By comparing it with
* your own nickname, you can check whether your PART
* command succeed.
* \param params[0] mandatory, contains the channel name.
* \param params[1] optional, contains the reason message (user-defined).
*/
irc_event_callback_t event_part;
/*!
* The "mode" event is triggered upon receipt of a channel MODE message,
* which means that someone on a channel with the client has changed the
* channel's parameters.
*
* \param origin the person, who changed the channel mode.
* \param params[0] mandatory, contains the channel name.
* \param params[1] mandatory, contains the changed channel mode, like
* '+t', '-i' and so on.
* \param params[2] optional, contains the mode argument (for example, a
* key for +k mode, or user who got the channel operator status for
* +o mode)
*/
irc_event_callback_t event_mode;
/*!
* The "umode" event is triggered upon receipt of a user MODE message,
* which means that your user mode has been changed.
*
* \param origin the person, who changed the channel mode.
* \param params[0] mandatory, contains the user changed mode, like
* '+t', '-i' and so on.
*/
irc_event_callback_t event_umode;
/*!
* The "topic" event is triggered upon receipt of a TOPIC message, which
* means that someone on a channel with the client has changed the
* channel's topic.
*
* \param origin the person, who changes the channel topic.
* \param params[0] mandatory, contains the channel name.
* \param params[1] optional, contains the new topic.
*/
irc_event_callback_t event_topic;
/*!
* The "kick" event is triggered upon receipt of a KICK message, which
* means that someone on a channel with the client (or possibly the
* client itself!) has been forcibly ejected.
*
* \param origin the person, who kicked the poor.
* \param params[0] mandatory, contains the channel name.
* \param params[0] optional, contains the nick of kicked person.
* \param params[1] optional, contains the kick text
*/
irc_event_callback_t event_kick;
/*!
* The "channel" event is triggered upon receipt of a PRIVMSG message
* to an entire channel, which means that someone on a channel with
* the client has said something aloud. Your own messages don't trigger
* PRIVMSG event.
*
* \param origin the person, who generates the message.
* \param params[0] mandatory, contains the channel name.
* \param params[1] optional, contains the message text
*/
irc_event_callback_t event_channel;
/*!
* The "privmsg" event is triggered upon receipt of a PRIVMSG message
* which is addressed to one or more clients, which means that someone
* is sending the client a private message.
*
* \param origin the person, who generates the message.
* \param params[0] mandatory, contains your nick.
* \param params[1] optional, contains the message text
*/
irc_event_callback_t event_privmsg;
/*!
* The "notice" event is triggered upon receipt of a NOTICE message
* which means that someone has sent the client a public or private
* notice. According to RFC 1459, the only difference between NOTICE
* and PRIVMSG is that you should NEVER automatically reply to NOTICE
* messages. Unfortunately, this rule is frequently violated by IRC
* servers itself - for example, NICKSERV messages require reply, and
* are NOTICEs.
*
* \param origin the person, who generates the message.
* \param params[0] mandatory, contains the target nick name.
* \param params[1] optional, contains the message text
*/
irc_event_callback_t event_notice;
/*!
* The "channel_notice" event is triggered upon receipt of a NOTICE
* message which means that someone has sent the client a public
* notice. According to RFC 1459, the only difference between NOTICE
* and PRIVMSG is that you should NEVER automatically reply to NOTICE
* messages. Unfortunately, this rule is frequently violated by IRC
* servers itself - for example, NICKSERV messages require reply, and
* are NOTICEs.
*
* \param origin the person, who generates the message.
* \param params[0] mandatory, contains the channel name.
* \param params[1] optional, contains the message text
*/
irc_event_callback_t event_channel_notice;
/*!
* The "invite" event is triggered upon receipt of an INVITE message,
* which means that someone is permitting the client's entry into a +i
* channel.
*
* \param origin the person, who INVITEs you.
* \param params[0] mandatory, contains your nick.
* \param params[1] mandatory, contains the channel name you're invited into.
*
* \sa irc_cmd_invite irc_cmd_chanmode_invite
*/
irc_event_callback_t event_invite;
/*!
* The "ctcp" event is triggered when the client receives the CTCP
* request. By default, the built-in CTCP request handler is used. The
* build-in handler automatically replies on most CTCP messages, so you
* will rarely need to override it.
*
* \param origin the person, who generates the message.
* \param params[0] mandatory, the complete CTCP message, including its
* arguments.
*
* Mirc generates PING, FINGER, VERSION, TIME and ACTION messages,
* check the source code of \c libirc_event_ctcp_internal function to
* see how to write your own CTCP request handler. Also you may find
* useful this question in FAQ: \ref faq4
*/
irc_event_callback_t event_ctcp_req;
/*!
* The "ctcp" event is triggered when the client receives the CTCP reply.
*
* \param origin the person, who generates the message.
* \param params[0] mandatory, the CTCP message itself with its arguments.
*/
irc_event_callback_t event_ctcp_rep;
/*!
* The "action" event is triggered when the client receives the CTCP
* ACTION message. These messages usually looks like:\n
* \code
* [23:32:55] * Tim gonna sleep.
* \endcode
*
* \param origin the person, who generates the message.
* \param params[0] mandatory, the ACTION message.
*/
irc_event_callback_t event_ctcp_action;
/*!
* The "unknown" event is triggered upon receipt of any number of
* unclassifiable miscellaneous messages, which aren't handled by the
* library.
*/
irc_event_callback_t event_unknown;
/*!
* The "numeric" event is triggered upon receipt of any numeric response
* from the server. There is a lot of such responses, see the full list
* here: \ref rfcnumbers.
*
* See the params in ::irc_eventcode_callback_t specification.
*/
irc_eventcode_callback_t event_numeric;
/*!
* The "dcc chat" event is triggered when someone requests a DCC CHAT from
* you.
*
* See the params in ::irc_event_dcc_chat_t specification.
*/
irc_event_dcc_chat_t event_dcc_chat_req;
/*!
* The "dcc chat" event is triggered when someone wants to send a file
* to you via DCC SEND request.
*
* See the params in ::irc_event_dcc_send_t specification.
*/
irc_event_dcc_send_t event_dcc_send_req;
} irc_callbacks_t;
#endif /* INCLUDE_IRC_EVENTS_H */

View File

@ -1,56 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#ifndef INCLUDE_IRC_OPTIONS_H
#define INCLUDE_IRC_OPTIONS_H
#ifndef IN_INCLUDE_LIBIRC_H
#error This file should not be included directly, include just libircclient.h
#endif
/*!
* enables additional debug output
* \ingroup options
*/
#define LIBIRC_OPTION_DEBUG (1 << 1)
/*! \brief allows to strip origins automatically.
*
* For every IRC server event, the event origin is sent in standard form:
* nick!host\@ircserver, i.e. like tim!home\@irc.freenet.org. Such origins
* can not be used in IRC commands, and need to be stripped (i.e. host and
* server part should be cut off) before using. This can be done either
* explicitly, by calling irc_target_get_nick(), or implicitly for all the
* events - by setting this option with irc_option_set().
* \ingroup options
*/
#define LIBIRC_OPTION_STRIPNICKS (1 << 2)
/*! \brief Disables the certificate verification for SSL connections
*
* By default the SSL connection authenticy is ensured by verifying that the certificate
* presented by the server is signed by a known trusted certificate authority. Since those
* typically cost money, some IRC servers use the self-signed certificates. They provide the
* benefits of the SSL connection but since they are not signed by the Certificate Authority,
* their authencity cannot be verified. This option, if set, disables the certificate
* verification - the library will accept any certificate presented by the server.
*
* This option must be set before the irc_connect function is called.
* \ingroup options
*/
#define LIBIRC_OPTION_SSL_NO_VERIFY (1 << 3)
#endif /* INCLUDE_IRC_OPTIONS_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,261 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ALLOCATORS_H_
#define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Allocator
/*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block.
Note that Malloc() and Realloc() are non-static but Free() is static.
So if an allocator need to support Free(), it needs to put its pointer in
the header of memory block.
\code
concept Allocator {
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
// Allocate a memory block.
// \param size of the memory block in bytes.
// \returns pointer to the memory block.
void* Malloc(size_t size);
// Resize a memory block.
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
// \param newSize the new size in bytes.
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
// Free a memory block.
// \param pointer to the memory block. Null pointer is permitted.
static void Free(void *ptr);
};
\endcode
*/
///////////////////////////////////////////////////////////////////////////////
// CrtAllocator
//! C-runtime library allocator.
/*! This class is just wrapper for standard C library memory routines.
\note implements Allocator concept
*/
class CrtAllocator {
public:
static const bool kNeedFree = true;
void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined.
return std::malloc(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
(void)originalSize;
if (newSize == 0) {
std::free(originalPtr);
return NULL;
}
return std::realloc(originalPtr, newSize);
}
static void Free(void *ptr) { std::free(ptr); }
};
///////////////////////////////////////////////////////////////////////////////
// MemoryPoolAllocator
//! Default memory allocator used by the parser and DOM.
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
It does not free memory blocks. And Realloc() only allocate new memory.
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
User may also supply a buffer as the first chunk.
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
The user-buffer is not deallocated by this allocator.
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
\note implements Allocator concept
*/
template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{
}
//! Constructor with user-supplied buffer.
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
The user buffer will not be deallocated when this allocator is destructed.
\param buffer User supplied buffer.
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{
RAPIDJSON_ASSERT(buffer != 0);
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
chunkHead_->capacity = size - sizeof(ChunkHeader);
chunkHead_->size = 0;
chunkHead_->next = 0;
}
//! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/
~MemoryPoolAllocator() {
Clear();
RAPIDJSON_DELETE(ownBaseAllocator_);
}
//! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() {
while (chunkHead_ && chunkHead_ != userBuffer_) {
ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_);
chunkHead_ = next;
}
if (chunkHead_ && chunkHead_ == userBuffer_)
chunkHead_->size = 0; // Clear user buffer
}
//! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes.
*/
size_t Capacity() const {
size_t capacity = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
capacity += c->capacity;
return capacity;
}
//! Computes the memory blocks allocated.
/*! \return total used bytes.
*/
size_t Size() const {
size_t size = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
size += c->size;
return size;
}
//! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) {
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size);
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
chunkHead_->size += size;
return buffer;
}
//! Resizes a memory block (concept Allocator)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
if (originalPtr == 0)
return Malloc(newSize);
if (newSize == 0)
return NULL;
// Do not shrink if new size is smaller than original
if (originalSize >= newSize)
return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize);
increment = RAPIDJSON_ALIGN(increment);
if (chunkHead_->size + increment <= chunkHead_->capacity) {
chunkHead_->size += increment;
return originalPtr;
}
}
// Realloc process: allocate and copy memory, do not free original buffer.
void* newBuffer = Malloc(newSize);
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
if (originalSize)
std::memcpy(newBuffer, originalPtr, originalSize);
return newBuffer;
}
//! Frees a memory block (concept Allocator)
static void Free(void *ptr) { (void)ptr; } // Do nothing
private:
//! Copy constructor is not permitted.
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
//! Copy assignment operator is not permitted.
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
//! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes.
*/
void AddChunk(size_t capacity) {
if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
chunk->capacity = capacity;
chunk->size = 0;
chunk->next = chunkHead_;
chunkHead_ = chunk;
}
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
//! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list.
*/
struct ChunkHeader {
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader *next; //!< Next chunk in the linked list.
};
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
void *userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,261 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
#define RAPIDJSON_ENCODEDSTREAM_H_
#include "rapidjson.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Input byte stream wrapper with a statically bound encoding.
/*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
*/
template <typename Encoding, typename InputByteStream>
class EncodedInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public:
typedef typename Encoding::Ch Ch;
EncodedInputStream(InputByteStream& is) : is_(is) {
current_ = Encoding::TakeBOM(is_);
}
Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
size_t Tell() const { return is_.Tell(); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&);
InputByteStream& is_;
Ch current_;
};
//! Output byte stream wrapper with statically bound encoding.
/*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileWriteStream.
*/
template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public:
typedef typename Encoding::Ch Ch;
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
if (putBOM)
Encoding::PutBOM(os_);
}
void Put(Ch c) { Encoding::Put(os_, c); }
void Flush() { os_.Flush(); }
// Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
EncodedOutputStream(const EncodedOutputStream&);
EncodedOutputStream& operator=(const EncodedOutputStream&);
OutputByteStream& os_;
};
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
\tparam CharType Type of character for reading.
\tparam InputByteStream type of input byte stream to be wrapped.
*/
template <typename CharType, typename InputByteStream>
class AutoUTFInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public:
typedef CharType Ch;
//! Constructor.
/*!
\param is input stream to be wrapped.
\param type UTF encoding type if it is not detected from the stream.
*/
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
DetectType();
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_];
current_ = takeFunc_(*is_);
}
UTFType GetType() const { return type_; }
bool HasBOM() const { return hasBOM_; }
Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
size_t Tell() const { return is_->Tell(); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
AutoUTFInputStream(const AutoUTFInputStream&);
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
// Detect encoding type with BOM or RFC 4627
void DetectType() {
// BOM (Byte Order Mark):
// 00 00 FE FF UTF-32BE
// FF FE 00 00 UTF-32LE
// FE FF UTF-16BE
// FF FE UTF-16LE
// EF BB BF UTF-8
const unsigned char* c = (const unsigned char *)is_->Peek4();
if (!c)
return;
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
// RFC 4627: Section 3
// "Since the first two characters of a JSON text will always be ASCII
// characters [RFC0020], it is possible to determine whether an octet
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
// at the pattern of nulls in the first four octets."
// 00 00 00 xx UTF-32BE
// 00 xx 00 xx UTF-16BE
// xx 00 00 00 UTF-32LE
// xx 00 xx 00 UTF-16LE
// xx xx xx xx UTF-8
if (!hasBOM_) {
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
switch (pattern) {
case 0x08: type_ = kUTF32BE; break;
case 0x0A: type_ = kUTF16BE; break;
case 0x01: type_ = kUTF32LE; break;
case 0x05: type_ = kUTF16LE; break;
case 0x0F: type_ = kUTF8; break;
default: break; // Use type defined by user.
}
}
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
}
typedef Ch (*TakeFunc)(InputByteStream& is);
InputByteStream* is_;
UTFType type_;
Ch current_;
TakeFunc takeFunc_;
bool hasBOM_;
};
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
\tparam CharType Type of character for writing.
\tparam InputByteStream type of output byte stream to be wrapped.
*/
template <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public:
typedef CharType Ch;
//! Constructor.
/*!
\param os output stream to be wrapped.
\param type UTF encoding type.
\param putBOM Whether to write BOM at the beginning of the stream.
*/
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_];
if (putBOM)
PutBOM();
}
UTFType GetType() const { return type_; }
void Put(Ch c) { putFunc_(*os_, c); }
void Flush() { os_->Flush(); }
// Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
AutoUTFOutputStream(const AutoUTFOutputStream&);
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
void PutBOM() {
typedef void (*PutBOMFunc)(OutputByteStream&);
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
f[type_](*os_);
}
typedef void (*PutFunc)(OutputByteStream&, Ch);
OutputByteStream* os_;
UTFType type_;
PutFunc putFunc_;
};
#undef RAPIDJSON_ENCODINGS_FUNC
RAPIDJSON_NAMESPACE_END
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_

View File

@ -1,625 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODINGS_H_
#define RAPIDJSON_ENCODINGS_H_
#include "rapidjson.h"
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
RAPIDJSON_DIAG_OFF(4702) // unreachable code
#elif defined(__GNUC__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(overflow)
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Encoding
/*! \class rapidjson::Encoding
\brief Concept for encoding of Unicode characters.
\code
concept Encoding {
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
//! \brief Encode a Unicode codepoint to an output stream.
//! \param os Output stream.
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint);
//! \brief Decode a Unicode codepoint from an input stream.
//! \param is Input stream.
//! \param codepoint Output of the unicode codepoint.
//! \return true if a valid codepoint can be decoded from the stream.
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint);
//! \brief Validate one Unicode codepoint from an encoded stream.
//! \param is Input stream to obtain codepoint.
//! \param os Output for copying one codepoint.
//! \return true if it is valid.
//! \note This function just validating and copying the codepoint without actually decode it.
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os);
// The following functions are deal with byte streams.
//! Take a character from input byte stream, skip BOM if exist.
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is);
//! Take a character from input byte stream.
template <typename InputByteStream>
static Ch Take(InputByteStream& is);
//! Put BOM to output byte stream.
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os);
//! Put a character to output byte stream.
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c);
};
\endcode
*/
///////////////////////////////////////////////////////////////////////////////
// UTF8
//! UTF-8 encoding.
/*! http://en.wikipedia.org/wiki/UTF-8
http://tools.ietf.org/html/rfc3629
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
\note implements Encoding concept
*/
template<typename CharType = char>
struct UTF8 {
typedef CharType Ch;
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
if (codepoint <= 0x7F)
os.Put(static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) {
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
}
else if (codepoint <= 0xFFFF) {
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70)
Ch c = is.Take();
if (!(c & 0x80)) {
*codepoint = (unsigned char)c;
return true;
}
unsigned char type = GetRange((unsigned char)c);
*codepoint = (0xFF >> type) & (unsigned char)c;
bool result = true;
switch (type) {
case 2: TAIL(); return result;
case 3: TAIL(); TAIL(); return result;
case 4: COPY(); TRANS(0x50); TAIL(); return result;
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
case 6: TAIL(); TAIL(); TAIL(); return result;
case 10: COPY(); TRANS(0x20); TAIL(); return result;
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
default: return false;
}
#undef COPY
#undef TRANS
#undef TAIL
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
#define COPY() os.Put(c = is.Take())
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70)
Ch c;
COPY();
if (!(c & 0x80))
return true;
bool result = true;
switch (GetRange((unsigned char)c)) {
case 2: TAIL(); return result;
case 3: TAIL(); TAIL(); return result;
case 4: COPY(); TRANS(0x50); TAIL(); return result;
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
case 6: TAIL(); TAIL(); TAIL(); return result;
case 10: COPY(); TRANS(0x20); TAIL(); return result;
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
default: return false;
}
#undef COPY
#undef TRANS
#undef TAIL
}
static unsigned char GetRange(unsigned char c) {
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
static const unsigned char type[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
};
return type[c];
}
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
Ch c = Take(is);
if ((unsigned char)c != 0xEFu) return c;
c = is.Take();
if ((unsigned char)c != 0xBBu) return c;
c = is.Take();
if ((unsigned char)c != 0xBFu) return c;
c = is.Take();
return c;
}
template <typename InputByteStream>
static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return is.Take();
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c));
}
};
///////////////////////////////////////////////////////////////////////////////
// UTF16
//! UTF-16 encoding.
/*! http://en.wikipedia.org/wiki/UTF-16
http://tools.ietf.org/html/rfc2781
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
\note implements Encoding concept
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF16LE and UTF16BE, which handle endianness.
*/
template<typename CharType = wchar_t>
struct UTF16 {
typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) {
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
os.Put((v & 0x3FF) | 0xDC00);
}
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
Ch c = is.Take();
if (c < 0xD800 || c > 0xDFFF) {
*codepoint = c;
return true;
}
else if (c <= 0xDBFF) {
*codepoint = (c & 0x3FF) << 10;
c = is.Take();
*codepoint |= (c & 0x3FF);
*codepoint += 0x10000;
return c >= 0xDC00 && c <= 0xDFFF;
}
return false;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
Ch c;
os.Put(c = is.Take());
if (c < 0xD800 || c > 0xDFFF)
return true;
else if (c <= 0xDBFF) {
os.Put(c = is.Take());
return c >= 0xDC00 && c <= 0xDFFF;
}
return false;
}
};
//! UTF-16 little endian encoding.
template<typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take();
c |= (unsigned char)is.Take() << 8;
return c;
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFFu); os.Put(0xFEu);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu);
os.Put((c >> 8) & 0xFFu);
}
};
//! UTF-16 big endian encoding.
template<typename CharType = wchar_t>
struct UTF16BE : UTF16<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take();
return c;
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFEu); os.Put(0xFFu);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put((c >> 8) & 0xFFu);
os.Put(c & 0xFFu);
}
};
///////////////////////////////////////////////////////////////////////////////
// UTF32
//! UTF-32 encoding.
/*! http://en.wikipedia.org/wiki/UTF-32
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
\note implements Encoding concept
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF32LE and UTF32BE, which handle endianness.
*/
template<typename CharType = unsigned>
struct UTF32 {
typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(codepoint);
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c = is.Take();
*codepoint = c;
return c <= 0x10FFFF;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c;
os.Put(c = is.Take());
return c <= 0x10FFFF;
}
};
//! UTF-32 little endian enocoding.
template<typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take();
c |= (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take() << 16;
c |= (unsigned char)is.Take() << 24;
return c;
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu);
os.Put((c >> 8) & 0xFFu);
os.Put((c >> 16) & 0xFFu);
os.Put((c >> 24) & 0xFFu);
}
};
//! UTF-32 big endian encoding.
template<typename CharType = unsigned>
struct UTF32BE : UTF32<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 24;
c |= (unsigned char)is.Take() << 16;
c |= (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take();
return c;
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put((c >> 24) & 0xFFu);
os.Put((c >> 16) & 0xFFu);
os.Put((c >> 8) & 0xFFu);
os.Put(c & 0xFFu);
}
};
///////////////////////////////////////////////////////////////////////////////
// ASCII
//! ASCII encoding.
/*! http://en.wikipedia.org/wiki/ASCII
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
\note implements Encoding concept
*/
template<typename CharType = char>
struct ASCII {
typedef CharType Ch;
enum { supportUnicode = 0 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_ASSERT(codepoint <= 0x7F);
os.Put(static_cast<Ch>(codepoint & 0xFF));
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
unsigned char c = static_cast<unsigned char>(is.Take());
*codepoint = c;
return c <= 0X7F;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
unsigned char c = is.Take();
os.Put(c);
return c <= 0x7F;
}
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
Ch c = Take(is);
return c;
}
template <typename InputByteStream>
static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return is.Take();
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
(void)os;
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c));
}
};
///////////////////////////////////////////////////////////////////////////////
// AutoUTF
//! Runtime-specified UTF encoding type of a stream.
enum UTFType {
kUTF8 = 0, //!< UTF-8.
kUTF16LE = 1, //!< UTF-16 little endian.
kUTF16BE = 2, //!< UTF-16 big endian.
kUTF32LE = 3, //!< UTF-32 little endian.
kUTF32BE = 4 //!< UTF-32 big endian.
};
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
*/
template<typename CharType>
struct AutoUTF {
typedef CharType Ch;
enum { supportUnicode = 1 };
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template<typename OutputStream>
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint);
}
template <typename InputStream>
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
return (*f[is.GetType()])(is, codepoint);
}
template <typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
return (*f[is.GetType()])(is, os);
}
#undef RAPIDJSON_ENCODINGS_FUNC
};
///////////////////////////////////////////////////////////////////////////////
// Transcoder
//! Encoding conversion.
template<typename SourceEncoding, typename TargetEncoding>
struct Transcoder {
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
TargetEncoding::Encode(os, codepoint);
return true;
}
//! Validate one Unicode codepoint from an encoded stream.
template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
return Transcode(is, os); // Since source/target encoding is different, must transcode.
}
};
//! Specialization of Transcoder with same source and target encoding.
template<typename Encoding>
struct Transcoder<Encoding, Encoding> {
template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true;
}
template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
return Encoding::Validate(is, os); // source/target encoding are the same
}
};
RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || defined(_MSV_VER)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_ENCODINGS_H_

View File

@ -1,65 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_EN_H__
#define RAPIDJSON_ERROR_EN_H__
#include "error.h"
RAPIDJSON_NAMESPACE_BEGIN
//! Maps error code of parsing into error message.
/*!
\ingroup RAPIDJSON_ERRORS
\param parseErrorCode Error code obtained in parsing.
\return the error message.
\note User can make a copy of this function for localization.
Using switch-case is safer for future modification of error codes.
*/
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
switch (parseErrorCode) {
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
default:
return RAPIDJSON_ERROR_STRING("Unknown error.");
}
}
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ERROR_EN_H__

View File

@ -1,146 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_ERROR_H__
#define RAPIDJSON_ERROR_ERROR_H__
#include "../rapidjson.h"
/*! \file error.h */
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ERROR_CHARTYPE
//! Character type of error messages.
/*! \ingroup RAPIDJSON_ERRORS
The default character type is \c char.
On Windows, user can define this macro as \c TCHAR for supporting both
unicode/non-unicode settings.
*/
#ifndef RAPIDJSON_ERROR_CHARTYPE
#define RAPIDJSON_ERROR_CHARTYPE char
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ERROR_STRING
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
/*! \ingroup RAPIDJSON_ERRORS
By default this conversion macro does nothing.
On Windows, user can define this macro as \c _T(x) for supporting both
unicode/non-unicode settings.
*/
#ifndef RAPIDJSON_ERROR_STRING
#define RAPIDJSON_ERROR_STRING(x) x
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// ParseErrorCode
//! Error code of parsing.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericReader::Parse, GenericReader::GetParseErrorCode
*/
enum ParseErrorCode {
kParseErrorNone = 0, //!< No error.
kParseErrorDocumentEmpty, //!< The document is empty.
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
kParseErrorValueInvalid, //!< Invalid value.
kParseErrorObjectMissName, //!< Missing a name for object member.
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
kParseErrorNumberMissExponent, //!< Miss exponent in number.
kParseErrorTermination, //!< Parsing was terminated.
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
};
//! Result of parsing (wraps ParseErrorCode)
/*!
\ingroup RAPIDJSON_ERRORS
\code
Document doc;
ParseResult ok = doc.Parse("[42]");
if (!ok) {
fprintf(stderr, "JSON parse error: %s (%u)",
GetParseError_En(ok.Code()), ok.Offset());
exit(EXIT_FAILURE);
}
\endcode
\see GenericReader::Parse, GenericDocument::Parse
*/
struct ParseResult {
//! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {}
//! Constructor to set an error.
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
//! Get the error code.
ParseErrorCode Code() const { return code_; }
//! Get the error offset, if \ref IsError(), 0 otherwise.
size_t Offset() const { return offset_; }
//! Conversion to \c bool, returns \c true, iff !\ref IsError().
operator bool() const { return !IsError(); }
//! Whether the result is an error.
bool IsError() const { return code_ != kParseErrorNone; }
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
bool operator==(ParseErrorCode code) const { return code_ == code; }
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
//! Reset error code.
void Clear() { Set(kParseErrorNone); }
//! Update error code and offset.
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
private:
ParseErrorCode code_;
size_t offset_;
};
//! Function pointer type of GetParseError().
/*! \ingroup RAPIDJSON_ERRORS
This is the prototype for \c GetParseError_X(), where \c X is a locale.
User can dynamically change locale in runtime, e.g.:
\code
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
\endcode
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ERROR_ERROR_H__

View File

@ -1,88 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEREADSTREAM_H_
#define RAPIDJSON_FILEREADSTREAM_H_
#include "rapidjson.h"
#include <cstdio>
RAPIDJSON_NAMESPACE_BEGIN
//! File byte stream for input using fread().
/*!
\note implements Stream concept
*/
class FileReadStream {
public:
typedef char Ch; //!< Character type (byte).
//! Constructor.
/*!
\param fp File pointer opened for read.
\param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes.
*/
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
RAPIDJSON_ASSERT(fp_ != 0);
RAPIDJSON_ASSERT(bufferSize >= 4);
Read();
}
Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; }
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
return (current_ + 4 <= bufferLast_) ? current_ : 0;
}
private:
void Read() {
if (current_ < bufferLast_)
++current_;
else if (!eof_) {
count_ += readCount_;
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
if (readCount_ < bufferSize_) {
buffer_[readCount_] = '\0';
++bufferLast_;
eof_ = true;
}
}
}
std::FILE* fp_;
Ch *buffer_;
size_t bufferSize_;
Ch *bufferLast_;
Ch *current_;
size_t readCount_;
size_t count_; //!< Number of characters read
bool eof_;
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_FILESTREAM_H_

View File

@ -1,95 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
#define RAPIDJSON_FILEWRITESTREAM_H_
#include "rapidjson.h"
#include <cstdio>
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of C file stream for input using fread().
/*!
\note implements Stream concept
*/
class FileWriteStream {
public:
typedef char Ch; //!< Character type. Only support char.
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
RAPIDJSON_ASSERT(fp_ != 0);
}
void Put(char c) {
if (current_ >= bufferEnd_)
Flush();
*current_++ = c;
}
void PutN(char c, size_t n) {
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
while (n > avail) {
std::memset(current_, c, avail);
current_ += avail;
Flush();
n -= avail;
avail = static_cast<size_t>(bufferEnd_ - current_);
}
if (n > 0) {
std::memset(current_, c, n);
current_ += n;
}
}
void Flush() {
if (current_ != buffer_) {
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
if (result < static_cast<size_t>(current_ - buffer_)) {
// failure deliberately ignored at this time
// added to avoid warn_unused_result build errors
}
current_ = buffer_;
}
}
// Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
char Take() { RAPIDJSON_ASSERT(false); return 0; }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
private:
// Prohibit copy constructor & assignment operator.
FileWriteStream(const FileWriteStream&);
FileWriteStream& operator=(const FileWriteStream&);
std::FILE* fp_;
char *buffer_;
char *bufferEnd_;
char *current_;
};
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(FileWriteStream& stream, char c, size_t n) {
stream.PutN(c, n);
}
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_FILESTREAM_H_

View File

@ -1,290 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_BIGINTEGER_H_
#define RAPIDJSON_BIGINTEGER_H_
#include "../rapidjson.h"
#if defined(_MSC_VER) && defined(_M_AMD64)
#include <intrin.h> // for _umul128
#pragma intrinsic(_umul128)
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
class BigInteger {
public:
typedef uint64_t Type;
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
explicit BigInteger(uint64_t u) : count_(1) {
digits_[0] = u;
}
BigInteger(const char* decimals, size_t length) : count_(1) {
RAPIDJSON_ASSERT(length > 0);
digits_[0] = 0;
size_t i = 0;
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
while (length >= kMaxDigitPerIteration) {
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
length -= kMaxDigitPerIteration;
i += kMaxDigitPerIteration;
}
if (length > 0)
AppendDecimal64(decimals + i, decimals + i + length);
}
BigInteger& operator=(const BigInteger &rhs)
{
if (this != &rhs) {
count_ = rhs.count_;
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
return *this;
}
BigInteger& operator=(uint64_t u) {
digits_[0] = u;
count_ = 1;
return *this;
}
BigInteger& operator+=(uint64_t u) {
Type backup = digits_[0];
digits_[0] += u;
for (size_t i = 0; i < count_ - 1; i++) {
if (digits_[i] >= backup)
return *this; // no carry
backup = digits_[i + 1];
digits_[i + 1] += 1;
}
// Last carry
if (digits_[count_ - 1] < backup)
PushBack(1);
return *this;
}
BigInteger& operator*=(uint64_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
uint64_t hi;
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
k = hi;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator*=(uint32_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF;
const uint64_t uc = u * c;
const uint64_t ud = u * d;
const uint64_t p0 = ud + k;
const uint64_t p1 = uc + (p0 >> 32);
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
k = p1 >> 32;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator<<=(size_t shift) {
if (IsZero() || shift == 0) return *this;
size_t offset = shift / kTypeBit;
size_t interShift = shift % kTypeBit;
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
if (interShift == 0) {
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
count_ += offset;
}
else {
digits_[count_] = 0;
for (size_t i = count_; i > 0; i--)
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
digits_[offset] = digits_[0] << interShift;
count_ += offset;
if (digits_[count_])
count_++;
}
std::memset(digits_, 0, offset * sizeof(Type));
return *this;
}
bool operator==(const BigInteger& rhs) const {
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
}
bool operator==(const Type rhs) const {
return count_ == 1 && digits_[0] == rhs;
}
BigInteger& MultiplyPow5(unsigned exp) {
static const uint32_t kPow5[12] = {
5,
5 * 5,
5 * 5 * 5,
5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
};
if (exp == 0) return *this;
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
if (exp > 0) *this *= kPow5[exp - 1];
return *this;
}
// Compute absolute difference of this and rhs.
// Assume this != rhs
bool Difference(const BigInteger& rhs, BigInteger* out) const {
int cmp = Compare(rhs);
RAPIDJSON_ASSERT(cmp != 0);
const BigInteger *a, *b; // Makes a > b
bool ret;
if (cmp < 0) { a = &rhs; b = this; ret = true; }
else { a = this; b = &rhs; ret = false; }
Type borrow = 0;
for (size_t i = 0; i < a->count_; i++) {
Type d = a->digits_[i] - borrow;
if (i < b->count_)
d -= b->digits_[i];
borrow = (d > a->digits_[i]) ? 1 : 0;
out->digits_[i] = d;
if (d != 0)
out->count_ = i + 1;
}
return ret;
}
int Compare(const BigInteger& rhs) const {
if (count_ != rhs.count_)
return count_ < rhs.count_ ? -1 : 1;
for (size_t i = count_; i-- > 0;)
if (digits_[i] != rhs.digits_[i])
return digits_[i] < rhs.digits_[i] ? -1 : 1;
return 0;
}
size_t GetCount() const { return count_; }
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
private:
void AppendDecimal64(const char* begin, const char* end) {
uint64_t u = ParseUint64(begin, end);
if (IsZero())
*this = u;
else {
unsigned exp = static_cast<unsigned>(end - begin);
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
}
}
void PushBack(Type digit) {
RAPIDJSON_ASSERT(count_ < kCapacity);
digits_[count_++] = digit;
}
static uint64_t ParseUint64(const char* begin, const char* end) {
uint64_t r = 0;
for (const char* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + (unsigned)(*p - '0');
}
return r;
}
// Assume a * b + k < 2^128
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t low = _umul128(a, b, outHigh) + k;
if (low < k)
(*outHigh)++;
return low;
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
p += k;
*outHigh = static_cast<uint64_t>(p >> 64);
return static_cast<uint64_t>(p);
#else
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
x1 += (x0 >> 32); // can't give carry
x1 += x2;
if (x1 < x2)
x3 += (static_cast<uint64_t>(1) << 32);
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
uint64_t hi = x3 + (x1 >> 32);
lo += k;
if (lo < k)
hi++;
*outHigh = hi;
return lo;
#endif
}
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
static const size_t kCapacity = kBitCount / sizeof(Type);
static const size_t kTypeBit = sizeof(Type) * 8;
Type digits_[kCapacity];
size_t count_;
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_BIGINTEGER_H_

View File

@ -1,248 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
#ifndef RAPIDJSON_DIYFP_H_
#define RAPIDJSON_DIYFP_H_
#include "../rapidjson.h"
#if defined(_MSC_VER) && defined(_M_AMD64)
#include <intrin.h>
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_umul128)
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
struct DiyFp {
DiyFp() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
explicit DiyFp(double d) {
union {
double d;
uint64_t u64;
} u = { d };
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) {
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
}
else {
f = significand;
e = kDpMinExponent + 1;
}
}
DiyFp operator-(const DiyFp& rhs) const {
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp& rhs) const {
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
uint64_t h = static_cast<uint64_t>(p >> 64);
uint64_t l = static_cast<uint64_t>(p);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#else
const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
tmp += 1U << 31; /// mult_round
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
#endif
}
DiyFp Normalize() const {
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__) && __GNUC__ >= 4
int s = __builtin_clzll(f);
return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
res.f <<= 1;
res.e--;
}
return res;
#endif
}
DiyFp NormalizeBoundary() const {
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
return res;
}
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
double ToDouble() const {
union {
double d;
uint64_t u64;
}u;
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d;
}
static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
static const int kDpMinExponent = -kDpExponentBias;
static const int kDpDenormalExponent = -kDpExponentBias + 1;
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
uint64_t f;
int e;
};
inline DiyFp GetCachedPowerByIndex(size_t index) {
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
};
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066
};
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
inline DiyFp GetCachedPower(int e, int* K) {
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if (dk - k > 0.0)
k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1);
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
return GetCachedPowerByIndex(index);
}
inline DiyFp GetCachedPower10(int exp, int *outExp) {
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
*outExp = -348 + static_cast<int>(index) * 8;
return GetCachedPowerByIndex(index);
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_DIYFP_H_

View File

@ -1,217 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
#ifndef RAPIDJSON_DTOA_
#define RAPIDJSON_DTOA_
#include "itoa.h" // GetDigitsLut()
#include "diyfp.h"
#include "ieee754.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
while (rest < wp_w && delta - rest >= ten_kappa &&
(rest + ten_kappa < wp_w || /// closer
wp_w - rest > rest + ten_kappa - wp_w)) {
buffer[len - 1]--;
rest += ten_kappa;
}
}
inline unsigned CountDecimalDigit32(uint32_t n) {
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
// Will not reach 10 digits in DigitGen()
//if (n < 1000000000) return 9;
//return 10;
return 9;
}
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1);
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0;
while (kappa > 0) {
uint32_t d = 0;
switch (kappa) {
case 9: d = p1 / 100000000; p1 %= 100000000; break;
case 8: d = p1 / 10000000; p1 %= 10000000; break;
case 7: d = p1 / 1000000; p1 %= 1000000; break;
case 6: d = p1 / 100000; p1 %= 100000; break;
case 5: d = p1 / 10000; p1 %= 10000; break;
case 4: d = p1 / 1000; p1 %= 1000; break;
case 3: d = p1 / 100; p1 %= 100; break;
case 2: d = p1 / 10; p1 %= 10; break;
case 1: d = p1; p1 = 0; break;
default:;
}
if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
kappa--;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta) {
*K += kappa;
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
return;
}
}
// kappa = 0
for (;;) {
p2 *= 10;
delta *= 10;
char d = static_cast<char>(p2 >> -one.e);
if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + d);
p2 &= one.f - 1;
kappa--;
if (p2 < delta) {
*K += kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]);
return;
}
}
}
inline void Grisu2(double value, char* buffer, int* length, int* K) {
const DiyFp v(value);
DiyFp w_m, w_p;
v.NormalizedBoundaries(&w_m, &w_p);
const DiyFp c_mk = GetCachedPower(w_p.e, K);
const DiyFp W = v.Normalize() * c_mk;
DiyFp Wp = w_p * c_mk;
DiyFp Wm = w_m * c_mk;
Wm.f++;
Wp.f--;
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
}
inline char* WriteExponent(int K, char* buffer) {
if (K < 0) {
*buffer++ = '-';
K = -K;
}
if (K >= 100) {
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
K %= 100;
const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else if (K >= 10) {
const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
return buffer;
}
inline char* Prettify(char* buffer, int length, int k) {
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (length <= kk && kk <= 21) {
// 1234e7 -> 12340000000
for (int i = length; i < kk; i++)
buffer[i] = '0';
buffer[kk] = '.';
buffer[kk + 1] = '0';
return &buffer[kk + 2];
}
else if (0 < kk && kk <= 21) {
// 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.';
return &buffer[length + 1];
}
else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234
const int offset = 2 - kk;
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
buffer[0] = '0';
buffer[1] = '.';
for (int i = 2; i < offset; i++)
buffer[i] = '0';
return &buffer[length + offset];
}
else if (length == 1) {
// 1e30
buffer[1] = 'e';
return WriteExponent(kk - 1, &buffer[2]);
}
else {
// 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
buffer[1] = '.';
buffer[length + 1] = 'e';
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
}
}
inline char* dtoa(double value, char* buffer) {
Double d(value);
if (d.IsZero()) {
if (d.Sign())
*buffer++ = '-'; // -0.0, Issue #289
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
}
else {
if (value < 0) {
*buffer++ = '-';
value = -value;
}
int length, K;
Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K);
}
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_DTOA_

View File

@ -1,77 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_IEEE754_
#define RAPIDJSON_IEEE754_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
class Double {
public:
Double() {}
Double(double d) : d_(d) {}
Double(uint64_t u) : u_(u) {}
double Value() const { return d_; }
uint64_t Uint64Value() const { return u_; }
double NextPositiveDouble() const {
RAPIDJSON_ASSERT(!Sign());
return Double(u_ + 1).Value();
}
bool Sign() const { return (u_ & kSignMask) != 0; }
uint64_t Significand() const { return u_ & kSignificandMask; }
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
static unsigned EffectiveSignificandSize(int order) {
if (order >= -1021)
return 53;
else if (order <= -1074)
return 0;
else
return (unsigned)order + 1074;
}
private:
static const int kSignificandSize = 52;
static const int kExponentBias = 0x3FF;
static const int kDenormalExponent = 1 - kExponentBias;
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
union {
double d_;
uint64_t u_;
};
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_IEEE754_

View File

@ -1,304 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ITOA_
#define RAPIDJSON_ITOA_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
inline const char* GetDigitsLut() {
static const char cDigitsLut[200] = {
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
};
return cDigitsLut;
}
inline char* u32toa(uint32_t value, char* buffer) {
const char* cDigitsLut = GetDigitsLut();
if (value < 10000) {
const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1;
if (value >= 1000)
*buffer++ = cDigitsLut[d1];
if (value >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else if (value < 100000000) {
// value = bbbbcccc
const uint32_t b = value / 10000;
const uint32_t c = value % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
else {
// value = aabbbbcccc in decimal
const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000;
if (a >= 10) {
const unsigned i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
const uint32_t b = value / 10000; // 0 to 9999
const uint32_t c = value % 10000; // 0 to 9999
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
return buffer;
}
inline char* i32toa(int32_t value, char* buffer) {
uint32_t u = static_cast<uint32_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
return u32toa(u, buffer);
}
inline char* u64toa(uint64_t value, char* buffer) {
const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10;
const uint64_t kTen10 = kTen8 * 100;
const uint64_t kTen11 = kTen8 * 1000;
const uint64_t kTen12 = kTen8 * 10000;
const uint64_t kTen13 = kTen8 * 100000;
const uint64_t kTen14 = kTen8 * 1000000;
const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8;
if (value < kTen8) {
uint32_t v = static_cast<uint32_t>(value);
if (v < 10000) {
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
if (v >= 1000)
*buffer++ = cDigitsLut[d1];
if (v >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (v >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else {
// value = bbbbcccc
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
}
else if (value < kTen16) {
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
if (value >= kTen15)
*buffer++ = cDigitsLut[d1];
if (value >= kTen14)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= kTen13)
*buffer++ = cDigitsLut[d2];
if (value >= kTen12)
*buffer++ = cDigitsLut[d2 + 1];
if (value >= kTen11)
*buffer++ = cDigitsLut[d3];
if (value >= kTen10)
*buffer++ = cDigitsLut[d3 + 1];
if (value >= kTen9)
*buffer++ = cDigitsLut[d4];
if (value >= kTen8)
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
else {
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
value %= kTen16;
if (a < 10)
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
else if (a < 100) {
const uint32_t i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else if (a < 1000) {
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else {
const uint32_t i = (a / 100) << 1;
const uint32_t j = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
*buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1];
}
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
return buffer;
}
inline char* i64toa(int64_t value, char* buffer) {
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
return u64toa(u, buffer);
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ITOA_

View File

@ -1,181 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_META_H_
#define RAPIDJSON_INTERNAL_META_H_
#include "../rapidjson.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
#if defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(6334)
#endif
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
#include <type_traits>
#endif
//@cond RAPIDJSON_INTERNAL
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
template <typename T> struct Void { typedef void Type; };
///////////////////////////////////////////////////////////////////////////////
// BoolType, TrueType, FalseType
//
template <bool Cond> struct BoolType {
static const bool Value = Cond;
typedef BoolType Type;
};
typedef BoolType<true> TrueType;
typedef BoolType<false> FalseType;
///////////////////////////////////////////////////////////////////////////////
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
//
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
template <> struct AndExprCond<true, true> : TrueType {};
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
template <> struct OrExprCond<false, false> : FalseType {};
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
///////////////////////////////////////////////////////////////////////////////
// AddConst, MaybeAddConst, RemoveConst
template <typename T> struct AddConst { typedef const T Type; };
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
template <typename T> struct RemoveConst { typedef T Type; };
template <typename T> struct RemoveConst<const T> { typedef T Type; };
///////////////////////////////////////////////////////////////////////////////
// IsSame, IsConst, IsMoreConst, IsPointer
//
template <typename T, typename U> struct IsSame : FalseType {};
template <typename T> struct IsSame<T, T> : TrueType {};
template <typename T> struct IsConst : FalseType {};
template <typename T> struct IsConst<const T> : TrueType {};
template <typename CT, typename T>
struct IsMoreConst
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
template <typename T> struct IsPointer : FalseType {};
template <typename T> struct IsPointer<T*> : TrueType {};
///////////////////////////////////////////////////////////////////////////////
// IsBaseOf
//
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
template <typename B, typename D> struct IsBaseOf
: BoolType< ::std::is_base_of<B,D>::value> {};
#else // simplified version adopted from Boost
template<typename B, typename D> struct IsBaseOfImpl {
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
typedef char (&Yes)[1];
typedef char (&No) [2];
template <typename T>
static Yes Check(const D*, T);
static No Check(const B*, int);
struct Host {
operator const B*() const;
operator const D*();
};
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
};
template <typename B, typename D> struct IsBaseOf
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
//////////////////////////////////////////////////////////////////////////
// EnableIf / DisableIf
//
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
template <typename Condition, typename T = void>
struct EnableIf : EnableIfCond<Condition::Value, T> {};
template <typename Condition, typename T = void>
struct DisableIf : DisableIfCond<Condition::Value, T> {};
// SFINAE helpers
struct SfinaeTag {};
template <typename T> struct RemoveSfinaeTag;
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
#define RAPIDJSON_REMOVEFPTR_(type) \
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
#define RAPIDJSON_ENABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_DISABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
} // namespace internal
RAPIDJSON_NAMESPACE_END
//@endcond
#if defined(__GNUC__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_INTERNAL_META_H_

View File

@ -1,55 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_POW10_
#define RAPIDJSON_POW10_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! Computes integer powers of 10 in double (10.0^n).
/*! This function uses lookup table for fast and accurate results.
\param n non-negative exponent. Must <= 308.
\return 10.0^n
*/
inline double Pow10(int n) {
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
1e+0,
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
};
RAPIDJSON_ASSERT(n >= 0 && n <= 308);
return e[n];
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_POW10_

View File

@ -1,196 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STACK_H_
#define RAPIDJSON_INTERNAL_STACK_H_
#include "../rapidjson.h"
#include "swap.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
///////////////////////////////////////////////////////////////////////////////
// Stack
//! A type-unsafe stack for storing different types of data.
/*! \tparam Allocator Allocator for allocating stack memory.
*/
template <typename Allocator>
class Stack {
public:
// Optimization note: Do not allocate memory for stack_ in constructor.
// Do it lazily when first Push() -> Expand() -> Resize().
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
RAPIDJSON_ASSERT(stackCapacity > 0);
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack(Stack&& rhs)
: allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_),
stack_(rhs.stack_),
stackTop_(rhs.stackTop_),
stackEnd_(rhs.stackEnd_),
initialCapacity_(rhs.initialCapacity_)
{
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.stack_ = 0;
rhs.stackTop_ = 0;
rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0;
}
#endif
~Stack() {
Destroy();
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack& operator=(Stack&& rhs) {
if (&rhs != this)
{
Destroy();
allocator_ = rhs.allocator_;
ownAllocator_ = rhs.ownAllocator_;
stack_ = rhs.stack_;
stackTop_ = rhs.stackTop_;
stackEnd_ = rhs.stackEnd_;
initialCapacity_ = rhs.initialCapacity_;
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.stack_ = 0;
rhs.stackTop_ = 0;
rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0;
}
return *this;
}
#endif
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
internal::Swap(allocator_, rhs.allocator_);
internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(stack_, rhs.stack_);
internal::Swap(stackTop_, rhs.stackTop_);
internal::Swap(stackEnd_, rhs.stackEnd_);
internal::Swap(initialCapacity_, rhs.initialCapacity_);
}
void Clear() { stackTop_ = stack_; }
void ShrinkToFit() {
if (Empty()) {
// If the stack is empty, completely deallocate the memory.
Allocator::Free(stack_);
stack_ = 0;
stackTop_ = 0;
stackEnd_ = 0;
}
else
Resize(GetSize());
}
// Optimization note: try to minimize the size of this function for force inline.
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
template<typename T>
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
// Expand the stack if needed
if (stackTop_ + sizeof(T) * count >= stackEnd_)
Expand<T>(count);
T* ret = reinterpret_cast<T*>(stackTop_);
stackTop_ += sizeof(T) * count;
return ret;
}
template<typename T>
T* Pop(size_t count) {
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
stackTop_ -= count * sizeof(T);
return reinterpret_cast<T*>(stackTop_);
}
template<typename T>
T* Top() {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
}
template<typename T>
T* Bottom() { return (T*)stack_; }
bool HasAllocator() const {
return allocator_ != 0;
}
Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_);
return *allocator_;
}
bool Empty() const { return stackTop_ == stack_; }
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
private:
template<typename T>
void Expand(size_t count) {
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
size_t newCapacity;
if (stack_ == 0) {
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
newCapacity = initialCapacity_;
} else {
newCapacity = GetCapacity();
newCapacity += (newCapacity + 1) / 2;
}
size_t newSize = GetSize() + sizeof(T) * count;
if (newCapacity < newSize)
newCapacity = newSize;
Resize(newCapacity);
}
void Resize(size_t newCapacity) {
const size_t size = GetSize(); // Backup the current size
stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
stackTop_ = stack_ + size;
stackEnd_ = stack_ + newCapacity;
}
void Destroy() {
Allocator::Free(stack_);
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
}
// Prohibit copy constructor & assignment operator.
Stack(const Stack&);
Stack& operator=(const Stack&);
Allocator* allocator_;
Allocator* ownAllocator_;
char *stack_;
char *stackTop_;
char *stackEnd_;
size_t initialCapacity_;
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STACK_H_

View File

@ -1,39 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
#define RAPIDJSON_INTERNAL_STRFUNC_H_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! Custom strlen() which works on different character types.
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
\param s Null-terminated input string.
\return Number of characters in the string.
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
*/
template <typename Ch>
inline SizeType StrLen(const Ch* s) {
const Ch* p = s;
while (*p) ++p;
return SizeType(p - s);
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_

View File

@ -1,270 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRTOD_
#define RAPIDJSON_STRTOD_
#include "../rapidjson.h"
#include "ieee754.h"
#include "biginteger.h"
#include "diyfp.h"
#include "pow10.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
inline double FastPath(double significand, int exp) {
if (exp < -308)
return 0.0;
else if (exp >= 0)
return significand * internal::Pow10(exp);
else
return significand / internal::Pow10(-exp);
}
inline double StrtodNormalPrecision(double d, int p) {
if (p < -308) {
// Prevent expSum < -308, making Pow10(p) = 0
d = FastPath(d, -308);
d = FastPath(d, p + 308);
}
else
d = FastPath(d, p);
return d;
}
template <typename T>
inline T Min3(T a, T b, T c) {
T m = a;
if (m > b) m = b;
if (m > c) m = c;
return m;
}
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
const Double db(b);
const uint64_t bInt = db.IntegerSignificand();
const int bExp = db.IntegerExponent();
const int hExp = bExp - 1;
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
// Adjust for decimal exponent
if (dExp >= 0) {
dS_Exp2 += dExp;
dS_Exp5 += dExp;
}
else {
bS_Exp2 -= dExp;
bS_Exp5 -= dExp;
hS_Exp2 -= dExp;
hS_Exp5 -= dExp;
}
// Adjust for binary exponent
if (bExp >= 0)
bS_Exp2 += bExp;
else {
dS_Exp2 -= bExp;
hS_Exp2 -= bExp;
}
// Adjust for half ulp exponent
if (hExp >= 0)
hS_Exp2 += hExp;
else {
dS_Exp2 -= hExp;
bS_Exp2 -= hExp;
}
// Remove common power of two factor from all three scaled values
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
dS_Exp2 -= common_Exp2;
bS_Exp2 -= common_Exp2;
hS_Exp2 -= common_Exp2;
BigInteger dS = d;
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
BigInteger bS(bInt);
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
BigInteger hS(1);
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
BigInteger delta(0);
dS.Difference(bS, &delta);
return delta.Compare(hS);
}
inline bool StrtodFast(double d, int p, double* result) {
// Use fast path for string-to-double conversion if possible
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
if (p > 22 && p < 22 + 16) {
// Fast Path Cases In Disguise
d *= internal::Pow10(p - 22);
p = 22;
}
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
*result = FastPath(d, p);
return true;
}
else
return false;
}
// Compute an approximation and see if it is within 1/2 ULP
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
uint64_t significand = 0;
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
for (; i < length; i++) {
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
break;
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
}
if (i < length && decimals[i] >= '5') // Rounding
significand++;
size_t remaining = length - i;
const unsigned kUlpShift = 3;
const unsigned kUlp = 1 << kUlpShift;
int error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0);
v = v.Normalize();
error <<= -v.e;
const int dExp = (int)decimalPosition - (int)i + exp;
int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) {
static const DiyFp kPow10[] = {
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
};
int adjustment = dExp - actualExp - 1;
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
v = v * kPow10[adjustment];
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
error += kUlp / 2;
}
v = v * cachedPower;
error += kUlp + (error == 0 ? 0 : 1);
const int oldExp = v.e;
v = v.Normalize();
error <<= oldExp - v.e;
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
unsigned precisionSize = 64 - effectiveSignificandSize;
if (precisionSize + kUlpShift >= 64) {
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp;
v.e += scaleExp;
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
precisionSize -= scaleExp;
}
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
rounded.f++;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
rounded.f >>= 1;
rounded.e++;
}
}
*result = rounded.ToDouble();
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
}
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
const BigInteger dInt(decimals, length);
const int dExp = (int)decimalPosition - (int)length + exp;
Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if (cmp < 0)
return a.Value(); // within half ULP
else if (cmp == 0) {
// Round towards even
if (a.Significand() & 1)
return a.NextPositiveDouble();
else
return a.Value();
}
else // adjustment
return a.NextPositiveDouble();
}
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1);
double result;
if (StrtodFast(d, p, &result))
return result;
// Trim leading zeros
while (*decimals == '0' && length > 1) {
length--;
decimals++;
decimalPosition--;
}
// Trim trailing zeros
while (decimals[length - 1] == '0' && length > 1) {
length--;
decimalPosition--;
exp++;
}
// Trim right-most digits
const int kMaxDecimalDigit = 780;
if ((int)length > kMaxDecimalDigit) {
int delta = (int(length) - kMaxDecimalDigit);
exp += delta;
decimalPosition -= static_cast<unsigned>(delta);
length = kMaxDecimalDigit;
}
// If too small, underflow to zero
if (int(length) + exp < -324)
return 0.0;
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
return result;
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STRTOD_

View File

@ -1,37 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
#define RAPIDJSON_INTERNAL_SWAP_H_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! Custom swap() to avoid dependency on C++ <algorithm> header
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
\note This has the same semantics as std::swap().
*/
template <typename T>
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
T tmp = a;
a = b;
b = tmp;
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_INTERNAL_SWAP_H_

View File

@ -1,70 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_MEMORYBUFFER_H_
#define RAPIDJSON_MEMORYBUFFER_H_
#include "rapidjson.h"
#include "internal/stack.h"
RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory output byte stream.
/*!
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
Differences between MemoryBuffer and StringBuffer:
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
\tparam Allocator type for allocating memory buffer.
\note implements Stream concept
*/
template <typename Allocator = CrtAllocator>
struct GenericMemoryBuffer {
typedef char Ch; // byte
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
void Flush() {}
void Clear() { stack_.Clear(); }
void ShrinkToFit() { stack_.ShrinkToFit(); }
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
const Ch* GetBuffer() const {
return stack_.template Bottom<Ch>();
}
size_t GetSize() const { return stack_.GetSize(); }
static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_;
};
typedef GenericMemoryBuffer<> MemoryBuffer;
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
}
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_MEMORYBUFFER_H_

View File

@ -1,61 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_MEMORYSTREAM_H_
#define RAPIDJSON_MEMORYSTREAM_H_
#include "rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory input byte stream.
/*!
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
Differences between MemoryStream and StringStream:
1. StringStream has encoding but MemoryStream is a byte stream.
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
\note implements Stream concept
*/
struct MemoryStream {
typedef char Ch; // byte
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
return Tell() + 4 <= size_ ? src_ : 0;
}
const Ch* src_; //!< Current read position.
const Ch* begin_; //!< Original head of the string.
const Ch* end_; //!< End of stream.
size_t size_; //!< Size of the stream.
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_MEMORYBUFFER_H_

View File

@ -1,316 +0,0 @@
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2013 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the product nor the names of its contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
// The above software in this distribution may have been modified by
// THL A29 Limited ("Tencent Modifications").
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_INTTYPES_H_ // [
#define _MSC_INTTYPES_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include "stdint.h"
// miloyip: VC supports inttypes.h since VC2013
#if _MSC_VER >= 1800
#include <inttypes.h>
#else
// 7.8 Format conversion of integer types
typedef struct {
intmax_t quot;
intmax_t rem;
} imaxdiv_t;
// 7.8.1 Macros for format specifiers
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
// The fprintf macros for signed integers are:
#define PRId8 "d"
#define PRIi8 "i"
#define PRIdLEAST8 "d"
#define PRIiLEAST8 "i"
#define PRIdFAST8 "d"
#define PRIiFAST8 "i"
#define PRId16 "hd"
#define PRIi16 "hi"
#define PRIdLEAST16 "hd"
#define PRIiLEAST16 "hi"
#define PRIdFAST16 "hd"
#define PRIiFAST16 "hi"
#define PRId32 "I32d"
#define PRIi32 "I32i"
#define PRIdLEAST32 "I32d"
#define PRIiLEAST32 "I32i"
#define PRIdFAST32 "I32d"
#define PRIiFAST32 "I32i"
#define PRId64 "I64d"
#define PRIi64 "I64i"
#define PRIdLEAST64 "I64d"
#define PRIiLEAST64 "I64i"
#define PRIdFAST64 "I64d"
#define PRIiFAST64 "I64i"
#define PRIdMAX "I64d"
#define PRIiMAX "I64i"
#define PRIdPTR "Id"
#define PRIiPTR "Ii"
// The fprintf macros for unsigned integers are:
#define PRIo8 "o"
#define PRIu8 "u"
#define PRIx8 "x"
#define PRIX8 "X"
#define PRIoLEAST8 "o"
#define PRIuLEAST8 "u"
#define PRIxLEAST8 "x"
#define PRIXLEAST8 "X"
#define PRIoFAST8 "o"
#define PRIuFAST8 "u"
#define PRIxFAST8 "x"
#define PRIXFAST8 "X"
#define PRIo16 "ho"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hX"
#define PRIoLEAST16 "ho"
#define PRIuLEAST16 "hu"
#define PRIxLEAST16 "hx"
#define PRIXLEAST16 "hX"
#define PRIoFAST16 "ho"
#define PRIuFAST16 "hu"
#define PRIxFAST16 "hx"
#define PRIXFAST16 "hX"
#define PRIo32 "I32o"
#define PRIu32 "I32u"
#define PRIx32 "I32x"
#define PRIX32 "I32X"
#define PRIoLEAST32 "I32o"
#define PRIuLEAST32 "I32u"
#define PRIxLEAST32 "I32x"
#define PRIXLEAST32 "I32X"
#define PRIoFAST32 "I32o"
#define PRIuFAST32 "I32u"
#define PRIxFAST32 "I32x"
#define PRIXFAST32 "I32X"
#define PRIo64 "I64o"
#define PRIu64 "I64u"
#define PRIx64 "I64x"
#define PRIX64 "I64X"
#define PRIoLEAST64 "I64o"
#define PRIuLEAST64 "I64u"
#define PRIxLEAST64 "I64x"
#define PRIXLEAST64 "I64X"
#define PRIoFAST64 "I64o"
#define PRIuFAST64 "I64u"
#define PRIxFAST64 "I64x"
#define PRIXFAST64 "I64X"
#define PRIoMAX "I64o"
#define PRIuMAX "I64u"
#define PRIxMAX "I64x"
#define PRIXMAX "I64X"
#define PRIoPTR "Io"
#define PRIuPTR "Iu"
#define PRIxPTR "Ix"
#define PRIXPTR "IX"
// The fscanf macros for signed integers are:
#define SCNd8 "d"
#define SCNi8 "i"
#define SCNdLEAST8 "d"
#define SCNiLEAST8 "i"
#define SCNdFAST8 "d"
#define SCNiFAST8 "i"
#define SCNd16 "hd"
#define SCNi16 "hi"
#define SCNdLEAST16 "hd"
#define SCNiLEAST16 "hi"
#define SCNdFAST16 "hd"
#define SCNiFAST16 "hi"
#define SCNd32 "ld"
#define SCNi32 "li"
#define SCNdLEAST32 "ld"
#define SCNiLEAST32 "li"
#define SCNdFAST32 "ld"
#define SCNiFAST32 "li"
#define SCNd64 "I64d"
#define SCNi64 "I64i"
#define SCNdLEAST64 "I64d"
#define SCNiLEAST64 "I64i"
#define SCNdFAST64 "I64d"
#define SCNiFAST64 "I64i"
#define SCNdMAX "I64d"
#define SCNiMAX "I64i"
#ifdef _WIN64 // [
# define SCNdPTR "I64d"
# define SCNiPTR "I64i"
#else // _WIN64 ][
# define SCNdPTR "ld"
# define SCNiPTR "li"
#endif // _WIN64 ]
// The fscanf macros for unsigned integers are:
#define SCNo8 "o"
#define SCNu8 "u"
#define SCNx8 "x"
#define SCNX8 "X"
#define SCNoLEAST8 "o"
#define SCNuLEAST8 "u"
#define SCNxLEAST8 "x"
#define SCNXLEAST8 "X"
#define SCNoFAST8 "o"
#define SCNuFAST8 "u"
#define SCNxFAST8 "x"
#define SCNXFAST8 "X"
#define SCNo16 "ho"
#define SCNu16 "hu"
#define SCNx16 "hx"
#define SCNX16 "hX"
#define SCNoLEAST16 "ho"
#define SCNuLEAST16 "hu"
#define SCNxLEAST16 "hx"
#define SCNXLEAST16 "hX"
#define SCNoFAST16 "ho"
#define SCNuFAST16 "hu"
#define SCNxFAST16 "hx"
#define SCNXFAST16 "hX"
#define SCNo32 "lo"
#define SCNu32 "lu"
#define SCNx32 "lx"
#define SCNX32 "lX"
#define SCNoLEAST32 "lo"
#define SCNuLEAST32 "lu"
#define SCNxLEAST32 "lx"
#define SCNXLEAST32 "lX"
#define SCNoFAST32 "lo"
#define SCNuFAST32 "lu"
#define SCNxFAST32 "lx"
#define SCNXFAST32 "lX"
#define SCNo64 "I64o"
#define SCNu64 "I64u"
#define SCNx64 "I64x"
#define SCNX64 "I64X"
#define SCNoLEAST64 "I64o"
#define SCNuLEAST64 "I64u"
#define SCNxLEAST64 "I64x"
#define SCNXLEAST64 "I64X"
#define SCNoFAST64 "I64o"
#define SCNuFAST64 "I64u"
#define SCNxFAST64 "I64x"
#define SCNXFAST64 "I64X"
#define SCNoMAX "I64o"
#define SCNuMAX "I64u"
#define SCNxMAX "I64x"
#define SCNXMAX "I64X"
#ifdef _WIN64 // [
# define SCNoPTR "I64o"
# define SCNuPTR "I64u"
# define SCNxPTR "I64x"
# define SCNXPTR "I64X"
#else // _WIN64 ][
# define SCNoPTR "lo"
# define SCNuPTR "lu"
# define SCNxPTR "lx"
# define SCNXPTR "lX"
#endif // _WIN64 ]
#endif // __STDC_FORMAT_MACROS ]
// 7.8.2 Functions for greatest-width integer types
// 7.8.2.1 The imaxabs function
#define imaxabs _abs64
// 7.8.2.2 The imaxdiv function
// This is modified version of div() function from Microsoft's div.c found
// in %MSVC.NET%\crt\src\div.c
#ifdef STATIC_IMAXDIV // [
static
#else // STATIC_IMAXDIV ][
_inline
#endif // STATIC_IMAXDIV ]
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
{
imaxdiv_t result;
result.quot = numer / denom;
result.rem = numer % denom;
if (numer < 0 && result.rem > 0) {
// did division wrong; must fix up
++result.quot;
result.rem -= denom;
}
return result;
}
// 7.8.2.3 The strtoimax and strtoumax functions
#define strtoimax _strtoi64
#define strtoumax _strtoui64
// 7.8.2.4 The wcstoimax and wcstoumax functions
#define wcstoimax _wcstoi64
#define wcstoumax _wcstoui64
#endif // _MSC_VER >= 1800
#endif // _MSC_INTTYPES_H_ ]

View File

@ -1,300 +0,0 @@
// ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2013 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the product nor the names of its contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
// The above software in this distribution may have been modified by
// THL A29 Limited ("Tencent Modifications").
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_STDINT_H_ // [
#define _MSC_STDINT_H_
#if _MSC_VER > 1000
#pragma once
#endif
// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
#if _MSC_VER >= 1600 // [
#include <stdint.h>
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
#undef INT8_C
#undef INT16_C
#undef INT32_C
#undef INT64_C
#undef UINT8_C
#undef UINT16_C
#undef UINT32_C
#undef UINT64_C
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
// Check out Issue 9 for the details.
#ifndef INTMAX_C // [
# define INTMAX_C INT64_C
#endif // INTMAX_C ]
#ifndef UINTMAX_C // [
# define UINTMAX_C UINT64_C
#endif // UINTMAX_C ]
#endif // __STDC_CONSTANT_MACROS ]
#else // ] _MSC_VER >= 1700 [
#include <limits.h>
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
// or compiler give many errors like this:
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#ifdef __cplusplus
extern "C" {
#endif
# include <wchar.h>
#ifdef __cplusplus
}
#endif
// Define _W64 macros to mark types changing their size, like intptr_t.
#ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
#endif
// 7.18.1 Integer types
// 7.18.1.1 Exact-width integer types
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
// realize that, e.g. char has the same size as __int8
// so we give up on __intX for them.
#if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#endif
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
// 7.18.1.2 Minimum-width integer types
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
// 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
// 7.18.1.4 Integer types capable of holding object pointers
#ifdef _WIN64 // [
typedef signed __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else // _WIN64 ][
typedef _W64 signed int intptr_t;
typedef _W64 unsigned int uintptr_t;
#endif // _WIN64 ]
// 7.18.1.5 Greatest-width integer types
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
// 7.18.2 Limits of specified-width integer types
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
// 7.18.2.1 Limits of exact-width integer types
#define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX
#define INT16_MIN ((int16_t)_I16_MIN)
#define INT16_MAX _I16_MAX
#define INT32_MIN ((int32_t)_I32_MIN)
#define INT32_MAX _I32_MAX
#define INT64_MIN ((int64_t)_I64_MIN)
#define INT64_MAX _I64_MAX
#define UINT8_MAX _UI8_MAX
#define UINT16_MAX _UI16_MAX
#define UINT32_MAX _UI32_MAX
#define UINT64_MAX _UI64_MAX
// 7.18.2.2 Limits of minimum-width integer types
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
// 7.18.2.3 Limits of fastest minimum-width integer types
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
// 7.18.2.4 Limits of integer types capable of holding object pointers
#ifdef _WIN64 // [
# define INTPTR_MIN INT64_MIN
# define INTPTR_MAX INT64_MAX
# define UINTPTR_MAX UINT64_MAX
#else // _WIN64 ][
# define INTPTR_MIN INT32_MIN
# define INTPTR_MAX INT32_MAX
# define UINTPTR_MAX UINT32_MAX
#endif // _WIN64 ]
// 7.18.2.5 Limits of greatest-width integer types
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
// 7.18.3 Limits of other integer types
#ifdef _WIN64 // [
# define PTRDIFF_MIN _I64_MIN
# define PTRDIFF_MAX _I64_MAX
#else // _WIN64 ][
# define PTRDIFF_MIN _I32_MIN
# define PTRDIFF_MAX _I32_MAX
#endif // _WIN64 ]
#define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX // [
# ifdef _WIN64 // [
# define SIZE_MAX _UI64_MAX
# else // _WIN64 ][
# define SIZE_MAX _UI32_MAX
# endif // _WIN64 ]
#endif // SIZE_MAX ]
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
#ifndef WCHAR_MIN // [
# define WCHAR_MIN 0
#endif // WCHAR_MIN ]
#ifndef WCHAR_MAX // [
# define WCHAR_MAX _UI16_MAX
#endif // WCHAR_MAX ]
#define WINT_MIN 0
#define WINT_MAX _UI16_MAX
#endif // __STDC_LIMIT_MACROS ]
// 7.18.4 Limits of other integer types
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
// Check out Issue 9 for the details.
#ifndef INTMAX_C // [
# define INTMAX_C INT64_C
#endif // INTMAX_C ]
#ifndef UINTMAX_C // [
# define UINTMAX_C UINT64_C
#endif // UINTMAX_C ]
#endif // __STDC_CONSTANT_MACROS ]
#endif // _MSC_VER >= 1600 ]
#endif // _MSC_STDINT_H_ ]

File diff suppressed because it is too large Load Diff

View File

@ -1,207 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_PRETTYWRITER_H_
#define RAPIDJSON_PRETTYWRITER_H_
#include "writer.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Writer with indentation and spacing.
/*!
\tparam OutputStream Type of ouptut os.
\tparam SourceEncoding Encoding of source string.
\tparam TargetEncoding Encoding of output stream.
\tparam StackAllocator Type of allocator for allocating memory of stack.
*/
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> {
public:
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
typedef typename Base::Ch Ch;
//! Constructor
/*! \param os Output stream.
\param allocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack.
*/
PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
//! Set custom indentation.
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
\param indentCharCount Number of indent characters for each indentation level.
\note The default indentation is 4 spaces.
*/
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
indentChar_ = indentChar;
indentCharCount_ = indentCharCount;
return *this;
}
/*! @name Implementation of Handler
\see Handler
*/
//@{
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
bool String(const Ch* str, SizeType length, bool copy = false) {
(void)copy;
PrettyPrefix(kStringType);
return Base::WriteString(str, length);
}
#if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) {
return String(str.data(), SizeType(str.size()));
}
#endif
bool StartObject() {
PrettyPrefix(kObjectType);
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
return Base::WriteStartObject();
}
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
bool EndObject(SizeType memberCount = 0) {
(void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) {
Base::os_->Put('\n');
WriteIndent();
}
bool ret = Base::WriteEndObject();
(void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush();
return true;
}
bool StartArray() {
PrettyPrefix(kArrayType);
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
return Base::WriteStartArray();
}
bool EndArray(SizeType memberCount = 0) {
(void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) {
Base::os_->Put('\n');
WriteIndent();
}
bool ret = Base::WriteEndArray();
(void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush();
return true;
}
//@}
/*! @name Convenience extensions */
//@{
//! Simpler but slower overload.
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
//@}
protected:
void PrettyPrefix(Type type) {
(void)type;
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
if (level->inArray) {
if (level->valueCount > 0) {
Base::os_->Put(','); // add comma if it is not the first element in array
Base::os_->Put('\n');
}
else
Base::os_->Put('\n');
WriteIndent();
}
else { // in object
if (level->valueCount > 0) {
if (level->valueCount % 2 == 0) {
Base::os_->Put(',');
Base::os_->Put('\n');
}
else {
Base::os_->Put(':');
Base::os_->Put(' ');
}
}
else
Base::os_->Put('\n');
if (level->valueCount % 2 == 0)
WriteIndent();
}
if (!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
level->valueCount++;
}
else {
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
Base::hasRoot_ = true;
}
}
void WriteIndent() {
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
PutN(*Base::os_, indentChar_, count);
}
Ch indentChar_;
unsigned indentCharCount_;
private:
// Prohibit copy constructor & assignment operator.
PrettyWriter(const PrettyWriter&);
PrettyWriter& operator=(const PrettyWriter&);
};
RAPIDJSON_NAMESPACE_END
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_RAPIDJSON_H_

View File

@ -1,654 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_RAPIDJSON_H_
#define RAPIDJSON_RAPIDJSON_H_
/*!\file rapidjson.h
\brief common definitions and configuration
\see RAPIDJSON_CONFIG
*/
/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
\brief Configuration macros for library features
Some RapidJSON features are configurable to adapt the library to a wide
variety of platforms, environments and usage scenarios. Most of the
features can be configured in terms of overriden or predefined
preprocessor macros at compile-time.
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
\note These macros should be given on the compiler command-line
(where applicable) to avoid inconsistent values when compiling
different translation units of a single application.
*/
#include <cstdlib> // malloc(), realloc(), free(), size_t
#include <cstring> // memset(), memcpy(), memmove(), memcmp()
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_VERSION_STRING
//
// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
//
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
// token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x
//!@endcond
/*! \def RAPIDJSON_MAJOR_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Major version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_MINOR_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Minor version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_PATCH_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Patch version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_VERSION_STRING
\ingroup RAPIDJSON_CONFIG
\brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
*/
#define RAPIDJSON_MAJOR_VERSION 1
#define RAPIDJSON_MINOR_VERSION 0
#define RAPIDJSON_PATCH_VERSION 2
#define RAPIDJSON_VERSION_STRING \
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NAMESPACE_(BEGIN|END)
/*! \def RAPIDJSON_NAMESPACE
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace
In order to avoid symbol clashes and/or "One Definition Rule" errors
between multiple inclusions of (different versions of) RapidJSON in
a single binary, users can customize the name of the main RapidJSON
namespace.
In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
RAPIDJSON_NAMESPACE_END need to be defined as well:
\code
// in some .cpp file
#define RAPIDJSON_NAMESPACE my::rapidjson
#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
#define RAPIDJSON_NAMESPACE_END } }
#include "rapidjson/..."
\endcode
\see rapidjson
*/
/*! \def RAPIDJSON_NAMESPACE_BEGIN
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace (opening expression)
\see RAPIDJSON_NAMESPACE
*/
/*! \def RAPIDJSON_NAMESPACE_END
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace (closing expression)
\see RAPIDJSON_NAMESPACE
*/
#ifndef RAPIDJSON_NAMESPACE
#define RAPIDJSON_NAMESPACE rapidjson
#endif
#ifndef RAPIDJSON_NAMESPACE_BEGIN
#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
#endif
#ifndef RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_NAMESPACE_END }
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NO_INT64DEFINE
/*! \def RAPIDJSON_NO_INT64DEFINE
\ingroup RAPIDJSON_CONFIG
\brief Use external 64-bit integer types.
RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
to be available at global scope.
If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
prevent RapidJSON from defining its own types.
*/
#ifndef RAPIDJSON_NO_INT64DEFINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#ifdef _MSC_VER
#include "msinttypes/stdint.h"
#include "msinttypes/inttypes.h"
#else
// Other compilers should have this.
#include <stdint.h>
#include <inttypes.h>
#endif
//!@endcond
#ifdef RAPIDJSON_DOXYGEN_RUNNING
#define RAPIDJSON_NO_INT64DEFINE
#endif
#endif // RAPIDJSON_NO_INT64TYPEDEF
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_FORCEINLINE
#ifndef RAPIDJSON_FORCEINLINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#if defined(_MSC_VER) && !defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __forceinline
#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
#else
#define RAPIDJSON_FORCEINLINE
#endif
//!@endcond
#endif // RAPIDJSON_FORCEINLINE
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ENDIAN
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
//! Endianness of the machine.
/*!
\def RAPIDJSON_ENDIAN
\ingroup RAPIDJSON_CONFIG
GCC 4.6 provided macro for detecting endianness of the target machine. But other
compilers may not have this. User can define RAPIDJSON_ENDIAN to either
\ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
Default detection implemented with reference to
\li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
\li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
*/
#ifndef RAPIDJSON_ENDIAN
// Detect with GCC 4.6's macro
# ifdef __BYTE_ORDER__
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __BYTE_ORDER__
// Detect with GLIBC's endian.h
# elif defined(__GLIBC__)
# include <endian.h>
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif (__BYTE_ORDER == __BIG_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __GLIBC__
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
// Detect with architecture macros
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN
# else
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
# endif
#endif // RAPIDJSON_ENDIAN
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_64BIT
//! Whether using 64-bit architecture
#ifndef RAPIDJSON_64BIT
#if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__)
#define RAPIDJSON_64BIT 1
#else
#define RAPIDJSON_64BIT 0
#endif
#endif // RAPIDJSON_64BIT
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ALIGN
//! Data alignment of the machine.
/*! \ingroup RAPIDJSON_CONFIG
\param x pointer to align
Some machines require strict data alignment. Currently the default uses 4 bytes
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
*/
#ifndef RAPIDJSON_ALIGN
#if RAPIDJSON_64BIT == 1
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
#else
#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_UINT64_C2
//! Construct a 64-bit literal by a pair of 32-bit integer.
/*!
64-bit literal with or without ULL suffix is prone to compiler warnings.
UINT64_C() is C macro which cause compilation problems.
Use this macro to define 64-bit constants by a pair of 32-bit integer.
*/
#ifndef RAPIDJSON_UINT64_C2
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
/*! \def RAPIDJSON_SIMD
\ingroup RAPIDJSON_CONFIG
\brief Enable SSE2/SSE4.2 optimization.
RapidJSON supports optimized implementations for some parsing operations
based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
processors.
To enable these optimizations, two different symbols can be defined;
\code
// Enable SSE2 optimization.
#define RAPIDJSON_SSE2
// Enable SSE4.2 optimization.
#define RAPIDJSON_SSE42
\endcode
\c RAPIDJSON_SSE42 takes precedence, if both are defined.
If any of these symbols is defined, RapidJSON defines the macro
\c RAPIDJSON_SIMD to indicate the availability of the optimized code.
*/
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
|| defined(RAPIDJSON_DOXYGEN_RUNNING)
#define RAPIDJSON_SIMD
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NO_SIZETYPEDEFINE
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
\ingroup RAPIDJSON_CONFIG
\brief User-provided \c SizeType definition.
In order to avoid using 32-bit size types for indexing strings and arrays,
define this preprocessor symbol and provide the type rapidjson::SizeType
before including RapidJSON:
\code
#define RAPIDJSON_NO_SIZETYPEDEFINE
namespace rapidjson { typedef ::std::size_t SizeType; }
#include "rapidjson/..."
\endcode
\see rapidjson::SizeType
*/
#ifdef RAPIDJSON_DOXYGEN_RUNNING
#define RAPIDJSON_NO_SIZETYPEDEFINE
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Size type (for string lengths, array sizes, etc.)
/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
instead of using \c size_t. Users may override the SizeType by defining
\ref RAPIDJSON_NO_SIZETYPEDEFINE.
*/
typedef unsigned SizeType;
RAPIDJSON_NAMESPACE_END
#endif
// always import std::size_t to rapidjson namespace
RAPIDJSON_NAMESPACE_BEGIN
using std::size_t;
RAPIDJSON_NAMESPACE_END
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ASSERT
//! Assertion.
/*! \ingroup RAPIDJSON_CONFIG
By default, rapidjson uses C \c assert() for internal assertions.
User can override it by defining RAPIDJSON_ASSERT(x) macro.
\note Parsing errors are handled and can be customized by the
\ref RAPIDJSON_ERRORS APIs.
*/
#ifndef RAPIDJSON_ASSERT
#include <cassert>
#define RAPIDJSON_ASSERT(x) assert(x)
#endif // RAPIDJSON_ASSERT
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_STATIC_ASSERT
// Adopt from boost
#ifndef RAPIDJSON_STATIC_ASSERT
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
RAPIDJSON_NAMESPACE_BEGIN
template <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
template<int x> struct StaticAssertTest {};
RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
#if defined(__GNUC__)
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
#else
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif
//!@endcond
/*! \def RAPIDJSON_STATIC_ASSERT
\brief (Internal) macro to check for conditions at compile-time
\param x compile-time condition
\hideinitializer
*/
#define RAPIDJSON_STATIC_ASSERT(x) \
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif
///////////////////////////////////////////////////////////////////////////////
// Helpers
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
#define RAPIDJSON_MULTILINEMACRO_END \
} while((void)0, 0)
// adopted from Boost
#define RAPIDJSON_VERSION_CODE(x,y,z) \
(((x)*100000) + ((y)*100) + (z))
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
#if defined(__GNUC__)
#define RAPIDJSON_GNUC \
RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
#endif
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
#define RAPIDJSON_DIAG_OFF(x) \
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
// push/pop support in Clang and GCC>=4.6
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
#else // GCC >= 4.2, < 4.6
#define RAPIDJSON_DIAG_PUSH /* ignored */
#define RAPIDJSON_DIAG_POP /* ignored */
#endif
#elif defined(_MSC_VER)
// pragma (MSVC specific)
#define RAPIDJSON_PRAGMA(x) __pragma(x)
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
#else
#define RAPIDJSON_DIAG_OFF(x) /* ignored */
#define RAPIDJSON_DIAG_PUSH /* ignored */
#define RAPIDJSON_DIAG_POP /* ignored */
#endif // RAPIDJSON_DIAG_*
///////////////////////////////////////////////////////////////////////////////
// C++11 features
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1600)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#else
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
#endif
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
#if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
#else
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
#endif
#endif
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
#define RAPIDJSON_NOEXCEPT noexcept
#else
#define RAPIDJSON_NOEXCEPT /* noexcept */
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
// no automatic detection, yet
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
#endif
//!@endcond
///////////////////////////////////////////////////////////////////////////////
// new/delete
#ifndef RAPIDJSON_NEW
///! customization point for global \c new
#define RAPIDJSON_NEW(x) new x
#endif
#ifndef RAPIDJSON_DELETE
///! customization point for global \c delete
#define RAPIDJSON_DELETE(x) delete x
#endif
///////////////////////////////////////////////////////////////////////////////
// Allocators and Encodings
#include "allocators.h"
#include "encodings.h"
/*! \namespace rapidjson
\brief main RapidJSON namespace
\see RAPIDJSON_NAMESPACE
*/
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Stream
/*! \class rapidjson::Stream
\brief Concept for reading and writing characters.
For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
For write-only stream, only need to implement Put() and Flush().
\code
concept Stream {
typename Ch; //!< Character type of the stream.
//! Read the current character from stream without moving the read cursor.
Ch Peek() const;
//! Read the current character from stream and moving the read cursor to next character.
Ch Take();
//! Get the current read cursor.
//! \return Number of characters read from start.
size_t Tell();
//! Begin writing operation at the current read pointer.
//! \return The begin writer pointer.
Ch* PutBegin();
//! Write a character.
void Put(Ch c);
//! Flush the buffer.
void Flush();
//! End the writing operation.
//! \param begin The begin write pointer returned by PutBegin().
//! \return Number of characters written.
size_t PutEnd(Ch* begin);
}
\endcode
*/
//! Provides additional information for stream.
/*!
By using traits pattern, this type provides a default configuration for stream.
For custom stream, this type can be specialized for other configuration.
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
*/
template<typename Stream>
struct StreamTraits {
//! Whether to make local copy of stream for optimization during parsing.
/*!
By default, for safety, streams do not use local copy optimization.
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
*/
enum { copyOptimization = 0 };
};
//! Put N copies of a character to a stream.
template<typename Stream, typename Ch>
inline void PutN(Stream& stream, Ch c, size_t n) {
for (size_t i = 0; i < n; i++)
stream.Put(c);
}
///////////////////////////////////////////////////////////////////////////////
// StringStream
//! Read-only string stream.
/*! \note implements Stream concept
*/
template <typename Encoding>
struct GenericStringStream {
typedef typename Encoding::Ch Ch;
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
Ch Peek() const { return *src_; }
Ch Take() { return *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
const Ch* src_; //!< Current read position.
const Ch* head_; //!< Original head of the string.
};
template <typename Encoding>
struct StreamTraits<GenericStringStream<Encoding> > {
enum { copyOptimization = 1 };
};
//! String stream with UTF8 encoding.
typedef GenericStringStream<UTF8<> > StringStream;
///////////////////////////////////////////////////////////////////////////////
// InsituStringStream
//! A read-write string stream.
/*! This string stream is particularly designed for in-situ parsing.
\note implements Stream concept
*/
template <typename Encoding>
struct GenericInsituStringStream {
typedef typename Encoding::Ch Ch;
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
// Read
Ch Peek() { return *src_; }
Ch Take() { return *src_++; }
size_t Tell() { return static_cast<size_t>(src_ - head_); }
// Write
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
Ch* PutBegin() { return dst_ = src_; }
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
void Flush() {}
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
void Pop(size_t count) { dst_ -= count; }
Ch* src_;
Ch* dst_;
Ch* head_;
};
template <typename Encoding>
struct StreamTraits<GenericInsituStringStream<Encoding> > {
enum { copyOptimization = 1 };
};
//! Insitu string stream with UTF8 encoding.
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
///////////////////////////////////////////////////////////////////////////////
// Type
//! Type of JSON value
enum Type {
kNullType = 0, //!< null
kFalseType = 1, //!< false
kTrueType = 2, //!< true
kObjectType = 3, //!< object
kArrayType = 4, //!< array
kStringType = 5, //!< string
kNumberType = 6 //!< number
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_RAPIDJSON_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRINGBUFFER_H_
#define RAPIDJSON_STRINGBUFFER_H_
#include "rapidjson.h"
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#include <utility> // std::move
#endif
#include "internal/stack.h"
RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory output stream.
/*!
\tparam Encoding Encoding of the stream.
\tparam Allocator type for allocating memory buffer.
\note implements Stream concept
*/
template <typename Encoding, typename Allocator = CrtAllocator>
class GenericStringBuffer {
public:
typedef typename Encoding::Ch Ch;
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
if (&rhs != this)
stack_ = std::move(rhs.stack_);
return *this;
}
#endif
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
void Flush() {}
void Clear() { stack_.Clear(); }
void ShrinkToFit() {
// Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0';
stack_.ShrinkToFit();
stack_.template Pop<Ch>(1);
}
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
const Ch* GetString() const {
// Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0';
stack_.template Pop<Ch>(1);
return stack_.template Bottom<Ch>();
}
size_t GetSize() const { return stack_.GetSize(); }
static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_;
private:
// Prohibit copy constructor & assignment operator.
GenericStringBuffer(const GenericStringBuffer&);
GenericStringBuffer& operator=(const GenericStringBuffer&);
};
//! String buffer with UTF8 encoding
typedef GenericStringBuffer<UTF8<> > StringBuffer;
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
}
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STRINGBUFFER_H_

View File

@ -1,395 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_WRITER_H_
#define RAPIDJSON_WRITER_H_
#include "rapidjson.h"
#include "internal/stack.h"
#include "internal/strfunc.h"
#include "internal/dtoa.h"
#include "internal/itoa.h"
#include "stringbuffer.h"
#include <new> // placement new
#if RAPIDJSON_HAS_STDSTRING
#include <string>
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! JSON writer
/*! Writer implements the concept Handler.
It generates JSON text by events to an output os.
User may programmatically calls the functions of a writer to generate JSON text.
On the other side, a writer can also be passed to objects that generates events,
for example Reader::Parse() and Document::Accept().
\tparam OutputStream Type of output stream.
\tparam SourceEncoding Encoding of source string.
\tparam TargetEncoding Encoding of output stream.
\tparam StackAllocator Type of allocator for allocating memory of stack.
\note implements Handler concept
*/
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
class Writer {
public:
typedef typename SourceEncoding::Ch Ch;
//! Constructor
/*! \param os Output stream.
\param stackAllocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack.
*/
explicit
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
explicit
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
//! Reset the writer with a new stream.
/*!
This function reset the writer with a new stream and default settings,
in order to make a Writer object reusable for output multiple JSONs.
\param os New output stream.
\code
Writer<OutputStream> writer(os1);
writer.StartObject();
// ...
writer.EndObject();
writer.Reset(os2);
writer.StartObject();
// ...
writer.EndObject();
\endcode
*/
void Reset(OutputStream& os) {
os_ = &os;
hasRoot_ = false;
level_stack_.Clear();
}
//! Checks whether the output is a complete JSON.
/*!
A complete JSON has a complete root object or array.
*/
bool IsComplete() const {
return hasRoot_ && level_stack_.Empty();
}
/*!@name Implementation of Handler
\see Handler
*/
//@{
bool Null() { Prefix(kNullType); return WriteNull(); }
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
//! Writes the given \c double value to the stream
/*!
\param d The value to be written.
\return Whether it is succeed.
*/
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
bool String(const Ch* str, SizeType length, bool copy = false) {
(void)copy;
Prefix(kStringType);
return WriteString(str, length);
}
#if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) {
return String(str.data(), SizeType(str.size()));
}
#endif
bool StartObject() {
Prefix(kObjectType);
new (level_stack_.template Push<Level>()) Level(false);
return WriteStartObject();
}
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
bool EndObject(SizeType memberCount = 0) {
(void)memberCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1);
bool ret = WriteEndObject();
if (level_stack_.Empty()) // end of json text
os_->Flush();
return ret;
}
bool StartArray() {
Prefix(kArrayType);
new (level_stack_.template Push<Level>()) Level(true);
return WriteStartArray();
}
bool EndArray(SizeType elementCount = 0) {
(void)elementCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1);
bool ret = WriteEndArray();
if (level_stack_.Empty()) // end of json text
os_->Flush();
return ret;
}
//@}
/*! @name Convenience extensions */
//@{
//! Simpler but slower overload.
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
//@}
protected:
//! Information for each nested level
struct Level {
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
size_t valueCount; //!< number of values in this level
bool inArray; //!< true if in array, otherwise in object
};
static const size_t kDefaultLevelDepth = 32;
bool WriteNull() {
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
}
bool WriteBool(bool b) {
if (b) {
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
}
else {
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
}
return true;
}
bool WriteInt(int i) {
char buffer[11];
const char* end = internal::i32toa(i, buffer);
for (const char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteUint(unsigned u) {
char buffer[10];
const char* end = internal::u32toa(u, buffer);
for (const char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteInt64(int64_t i64) {
char buffer[21];
const char* end = internal::i64toa(i64, buffer);
for (const char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteUint64(uint64_t u64) {
char buffer[20];
char* end = internal::u64toa(u64, buffer);
for (char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteDouble(double d) {
char buffer[25];
char* end = internal::dtoa(d, buffer);
for (char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteString(const Ch* str, SizeType length) {
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
static const char escape[256] = {
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
//0 1 2 3 4 5 6 7 8 9 A B C D E F
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
Z16, Z16, // 30~4F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
#undef Z16
};
os_->Put('\"');
GenericStringStream<SourceEncoding> is(str);
while (is.Tell() < length) {
const Ch c = is.Peek();
if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {
// Unicode escaping
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
os_->Put('\\');
os_->Put('u');
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
os_->Put(hexDigits[(codepoint >> 12) & 15]);
os_->Put(hexDigits[(codepoint >> 8) & 15]);
os_->Put(hexDigits[(codepoint >> 4) & 15]);
os_->Put(hexDigits[(codepoint ) & 15]);
}
else {
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
// Surrogate pair
unsigned s = codepoint - 0x010000;
unsigned lead = (s >> 10) + 0xD800;
unsigned trail = (s & 0x3FF) + 0xDC00;
os_->Put(hexDigits[(lead >> 12) & 15]);
os_->Put(hexDigits[(lead >> 8) & 15]);
os_->Put(hexDigits[(lead >> 4) & 15]);
os_->Put(hexDigits[(lead ) & 15]);
os_->Put('\\');
os_->Put('u');
os_->Put(hexDigits[(trail >> 12) & 15]);
os_->Put(hexDigits[(trail >> 8) & 15]);
os_->Put(hexDigits[(trail >> 4) & 15]);
os_->Put(hexDigits[(trail ) & 15]);
}
}
else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
is.Take();
os_->Put('\\');
os_->Put(escape[(unsigned char)c]);
if (escape[(unsigned char)c] == 'u') {
os_->Put('0');
os_->Put('0');
os_->Put(hexDigits[(unsigned char)c >> 4]);
os_->Put(hexDigits[(unsigned char)c & 0xF]);
}
}
else
if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
return false;
}
os_->Put('\"');
return true;
}
bool WriteStartObject() { os_->Put('{'); return true; }
bool WriteEndObject() { os_->Put('}'); return true; }
bool WriteStartArray() { os_->Put('['); return true; }
bool WriteEndArray() { os_->Put(']'); return true; }
void Prefix(Type type) {
(void)type;
if (level_stack_.GetSize() != 0) { // this value is not at root
Level* level = level_stack_.template Top<Level>();
if (level->valueCount > 0) {
if (level->inArray)
os_->Put(','); // add comma if it is not the first element in array
else // in object
os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
}
if (!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
level->valueCount++;
}
else {
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
hasRoot_ = true;
}
}
OutputStream* os_;
internal::Stack<StackAllocator> level_stack_;
bool hasRoot_;
private:
// Prohibit copy constructor & assignment operator.
Writer(const Writer&);
Writer& operator=(const Writer&);
};
// Full specialization for StringStream to prevent memory copying
template<>
inline bool Writer<StringBuffer>::WriteInt(int i) {
char *buffer = os_->Push(11);
const char* end = internal::i32toa(i, buffer);
os_->Pop(static_cast<size_t>(11 - (end - buffer)));
return true;
}
template<>
inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
char *buffer = os_->Push(10);
const char* end = internal::u32toa(u, buffer);
os_->Pop(static_cast<size_t>(10 - (end - buffer)));
return true;
}
template<>
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
char *buffer = os_->Push(21);
const char* end = internal::i64toa(i64, buffer);
os_->Pop(static_cast<size_t>(21 - (end - buffer)));
return true;
}
template<>
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
char *buffer = os_->Push(20);
const char* end = internal::u64toa(u, buffer);
os_->Pop(static_cast<size_t>(20 - (end - buffer)));
return true;
}
template<>
inline bool Writer<StringBuffer>::WriteDouble(double d) {
char *buffer = os_->Push(25);
char* end = internal::dtoa(d, buffer);
os_->Pop(static_cast<size_t>(25 - (end - buffer)));
return true;
}
RAPIDJSON_NAMESPACE_END
#ifdef _MSC_VER
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_RAPIDJSON_H_

View File

@ -111,9 +111,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.9.1"
#define SQLITE_VERSION_NUMBER 3009001
#define SQLITE_SOURCE_ID "2015-10-16 17:31:12 767c1727fec4ce11b83f25b3f1bfcfe68a2c8b02"
#define SQLITE_VERSION "3.11.0"
#define SQLITE_VERSION_NUMBER 3011000
#define SQLITE_SOURCE_ID "2016-02-15 17:29:24 3d862f207e3adc00f78066799ac5a8c282430a5f"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -347,7 +347,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** from [sqlite3_malloc()] and passed back through the 5th parameter.
** To avoid memory leaks, the application should invoke [sqlite3_free()]
** on error message strings returned through the 5th parameter of
** of sqlite3_exec() after the error message string is no longer needed.
** sqlite3_exec() after the error message string is no longer needed.
** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
** NULL before returning.
@ -478,6 +478,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8))
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
@ -793,8 +794,13 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_FILE_POINTER]]
** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
** to the [sqlite3_file] object associated with a particular database
** connection. See the [sqlite3_file_control()] documentation for
** additional information.
** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER].
**
** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
** to the [sqlite3_file] object associated with the journal file (either
** the [rollback journal] or the [write-ahead log]) for a particular database
** connection. See also [SQLITE_FCNTL_FILE_POINTER].
**
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
** No longer in use.
@ -881,6 +887,15 @@ struct sqlite3_io_methods {
** pointer in case this file-control is not implemented. This file-control
** is intended for diagnostic use only.
**
** <li>[[SQLITE_FCNTL_VFS_POINTER]]
** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level
** [VFSes] currently in use. ^(The argument X in
** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be
** of type "[sqlite3_vfs] **". This opcodes will set *X
** to a pointer to the top-level VFS.)^
** ^When there are multiple VFS shims in the stack, this opcode finds the
** upper-most shim only.
**
** <li>[[SQLITE_FCNTL_PRAGMA]]
** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
** file control is sent to the open [sqlite3_file] object corresponding
@ -999,6 +1014,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_WAL_BLOCK 24
#define SQLITE_FCNTL_ZIPVFS 25
#define SQLITE_FCNTL_RBU 26
#define SQLITE_FCNTL_VFS_POINTER 27
#define SQLITE_FCNTL_JOURNAL_POINTER 28
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@ -1598,29 +1615,34 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
** that SQLite can use for the database page cache with the default page
** cache implementation.
** This configuration should not be used if an application-define page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
** configuration option.
** This configuration option is a no-op if an application-define page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** 8-byte aligned memory (pMem), the size of each page cache line (sz),
** and the number of cache lines (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 65536) plus some extra bytes for each
** page header. ^The number of extra bytes needed by the page header
** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
** to [sqlite3_config()].
** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ].
** ^It is harmless, apart from the wasted memory,
** for the sz parameter to be larger than necessary. The first
** argument should pointer to an 8-byte aligned block of memory that
** is at least sz*N bytes of memory, otherwise subsequent behavior is
** undefined.
** ^SQLite will use the memory provided by the first argument to satisfy its
** memory needs for the first N pages that it adds to cache. ^If additional
** page cache memory is needed beyond what is provided by this option, then
** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
** for the sz parameter to be larger than necessary. The pMem
** argument must be either a NULL pointer or a pointer to an 8-byte
** aligned block of memory of at least sz*N bytes, otherwise
** subsequent behavior is undefined.
** ^When pMem is not NULL, SQLite will strive to use the memory provided
** to satisfy page cache needs, falling back to [sqlite3_malloc()] if
** a page cache line is larger than sz bytes or if all of the pMem buffer
** is exhausted.
** ^If pMem is NULL and N is non-zero, then each database connection
** does an initial bulk allocation for page cache memory
** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or
** of -1024*N bytes if N is negative, . ^If additional
** page cache memory is needed beyond what is provided by the initial
** allocation, then SQLite goes to [sqlite3_malloc()] separately for each
** additional cache line. </dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
@ -4389,8 +4411,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
** then sqlite3_value_free(V) is a harmless no-op.
*/
SQLITE_API SQLITE_EXPERIMENTAL sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
/*
** CAPI3REF: Obtain Aggregate Function Context
@ -5609,6 +5631,17 @@ struct sqlite3_module {
** ^Information about the ORDER BY clause is stored in aOrderBy[].
** ^Each term of aOrderBy records a column of the ORDER BY clause.
**
** The colUsed field indicates which columns of the virtual table may be
** required by the current scan. Virtual table columns are numbered from
** zero in the order in which they appear within the CREATE TABLE statement
** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62),
** the corresponding bit is set within the colUsed mask if the column may be
** required by SQLite. If the table has at least 64 columns and any column
** to the right of the first 63 is required, then bit 63 of colUsed is also
** set. In other words, column iCol may be required if the expression
** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
** non-zero.
**
** The [xBestIndex] method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter. ^If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
@ -5664,7 +5697,7 @@ struct sqlite3_index_info {
/* Inputs */
int nConstraint; /* Number of entries in aConstraint */
struct sqlite3_index_constraint {
int iColumn; /* Column on left-hand side of constraint */
int iColumn; /* Column constrained. -1 for ROWID */
unsigned char op; /* Constraint operator */
unsigned char usable; /* True if this constraint is usable */
int iTermOffset; /* Used internally - xBestIndex should ignore */
@ -5688,6 +5721,8 @@ struct sqlite3_index_info {
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
/* Fields below are only available in SQLite 3.9.0 and later */
int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */
/* Fields below are only available in SQLite 3.10.0 and later */
sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */
};
/*
@ -5703,12 +5738,15 @@ struct sqlite3_index_info {
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
#define SQLITE_INDEX_CONSTRAINT_LE 8
#define SQLITE_INDEX_CONSTRAINT_LT 16
#define SQLITE_INDEX_CONSTRAINT_GE 32
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
#define SQLITE_INDEX_CONSTRAINT_LE 8
#define SQLITE_INDEX_CONSTRAINT_LT 16
#define SQLITE_INDEX_CONSTRAINT_GE 32
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
#define SQLITE_INDEX_CONSTRAINT_LIKE 65
#define SQLITE_INDEX_CONSTRAINT_GLOB 66
#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
/*
** CAPI3REF: Register A Virtual Table Implementation
@ -6572,7 +6610,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
** <dd>This parameter records the deepest parser stack. It is only
** <dd>The *pHighwater parameter records the deepest parser stack.
** The *pCurrent value is undefined. The *pHighwater value is only
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
** </dl>
**
@ -7358,18 +7397,43 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
*
** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
** the glob pattern P, and it returns non-zero if string X does not match
** the glob pattern P. ^The definition of glob pattern matching used in
** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if
** string X matches the [GLOB] pattern P.
** ^The definition of [GLOB] pattern matching used in
** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case
** sensitive.
** SQL dialect understood by SQLite. ^The [sqlite3_strglob(P,X)] function
** is case sensitive.
**
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
**
** See also: [sqlite3_strlike()].
*/
SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
/*
** CAPI3REF: String LIKE Matching
*
** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if
** string X matches the [LIKE] pattern P with escape character E.
** ^The definition of [LIKE] pattern matching used in
** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E"
** operator in the SQL dialect understood by SQLite. ^For "X LIKE P" without
** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0.
** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case
** insensitive - equivalent upper and lower case ASCII characters match
** one another.
**
** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though
** only ASCII characters are case folded.
**
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
**
** See also: [sqlite3_strglob()].
*/
SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
/*
** CAPI3REF: Error Logging Interface
**
@ -7790,6 +7854,129 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
*/
SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
** CAPI3REF: Flush caches to disk mid-transaction
**
** ^If a write-transaction is open on [database connection] D when the
** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
** pages in the pager-cache that are not currently in use are written out
** to disk. A dirty page may be in use if a database cursor created by an
** active SQL statement is reading from it, or if it is page 1 of a database
** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)]
** interface flushes caches for all schemas - "main", "temp", and
** any [attached] databases.
**
** ^If this function needs to obtain extra database locks before dirty pages
** can be flushed to disk, it does so. ^If those locks cannot be obtained
** immediately and there is a busy-handler callback configured, it is invoked
** in the usual manner. ^If the required lock still cannot be obtained, then
** the database is skipped and an attempt made to flush any dirty pages
** belonging to the next (if any) database. ^If any databases are skipped
** because locks cannot be obtained, but no other error occurs, this
** function returns SQLITE_BUSY.
**
** ^If any other error occurs while flushing dirty pages to disk (for
** example an IO error or out-of-memory condition), then processing is
** abandoned and an SQLite [error code] is returned to the caller immediately.
**
** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK.
**
** ^This function does not set the database handle error code or message
** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*);
/*
** CAPI3REF: Database Snapshot
** KEYWORDS: {snapshot}
** EXPERIMENTAL
**
** An instance of the snapshot object records the state of a [WAL mode]
** database for some specific point in history.
**
** In [WAL mode], multiple [database connections] that are open on the
** same database file can each be reading a different historical version
** of the database file. When a [database connection] begins a read
** transaction, that connection sees an unchanging copy of the database
** as it existed for the point in time when the transaction first started.
** Subsequent changes to the database from other connections are not seen
** by the reader until a new read transaction is started.
**
** The sqlite3_snapshot object records state information about an historical
** version of the database file so that it is possible to later open a new read
** transaction that sees that historical version of the database rather than
** the most recent version.
**
** The constructor for this object is [sqlite3_snapshot_get()]. The
** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
** to an historical snapshot (if possible). The destructor for
** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
*/
typedef struct sqlite3_snapshot sqlite3_snapshot;
/*
** CAPI3REF: Record A Database Snapshot
** EXPERIMENTAL
**
** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
** new [sqlite3_snapshot] object that records the current state of
** schema S in database connection D. ^On success, the
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
** ^If schema S of [database connection] D is not a [WAL mode] database
** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
** leaves the *P value unchanged and returns an appropriate [error code].
**
** The [sqlite3_snapshot] object returned from a successful call to
** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
** to avoid a memory leak.
**
** The [sqlite3_snapshot_get()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get(
sqlite3 *db,
const char *zSchema,
sqlite3_snapshot **ppSnapshot
);
/*
** CAPI3REF: Start a read transaction on an historical snapshot
** EXPERIMENTAL
**
** ^The [sqlite3_snapshot_open(D,S,P)] interface attempts to move the
** read transaction that is currently open on schema S of
** [database connection] D so that it refers to historical [snapshot] P.
** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
** or an appropriate [error code] if it fails.
**
** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
** the first operation, apart from other sqlite3_snapshot_open() calls,
** following the [BEGIN] that starts a new read transaction.
** ^A [snapshot] will fail to open if it has been overwritten by a
** [checkpoint].
**
** The [sqlite3_snapshot_open()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open(
sqlite3 *db,
const char *zSchema,
sqlite3_snapshot *pSnapshot
);
/*
** CAPI3REF: Destroy a snapshot
** EXPERIMENTAL
**
** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
** The application must eventually free every [sqlite3_snapshot] object
** using this routine to avoid a memory leak.
**
** The [sqlite3_snapshot_free()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot*);
/*
** Undo the hack that converts floating point types to integer for
@ -8006,6 +8193,9 @@ struct Fts5PhraseIter {
** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** This function may be quite inefficient if used with an FTS5 table
** created with the "columnsize=0" option.
**
** xColumnText:
** This function attempts to retrieve the text of column iCol of the
** current document. If successful, (*pz) is set to point to a buffer
@ -8026,15 +8216,29 @@ struct Fts5PhraseIter {
** the query within the current row. Return SQLITE_OK if successful, or
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option. If the FTS5 table is created
** with either "detail=none" or "detail=column" and "content=" option
** (i.e. if it is a contentless table), then this API always returns 0.
**
** xInst:
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
** output by xInstCount().
**
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
** first token of the phrase. The exception is if the table was created
** with the offsets=0 option specified. In this case *piOff is always
** set to -1.
**
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
** if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
**
** xRowid:
** Returns the rowid of the current row.
**
@ -8118,7 +8322,7 @@ struct Fts5PhraseIter {
** Fts5PhraseIter iter;
** int iCol, iOff;
** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
** iOff>=0;
** iCol>=0;
** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
** ){
** // An instance of phrase iPhrase at offset iOff of column iCol
@ -8126,13 +8330,51 @@ struct Fts5PhraseIter {
**
** The Fts5PhraseIter structure is defined above. Applications should not
** modify this structure directly - it should only be used as shown above
** with the xPhraseFirst() and xPhraseNext() API methods.
** with the xPhraseFirst() and xPhraseNext() API methods (and by
** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option. If the FTS5 table is created
** with either "detail=none" or "detail=column" and "content=" option
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
** xPhraseNext()
** See xPhraseFirst above.
**
** xPhraseFirstColumn()
** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
** and xPhraseNext() APIs described above. The difference is that instead
** of iterating through all instances of a phrase in the current row, these
** APIs are used to iterate through the set of columns in the current row
** that contain one or more instances of a specified phrase. For example:
**
** Fts5PhraseIter iter;
** int iCol;
** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
** iCol>=0;
** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
** ){
** // Column iCol contains at least one instance of phrase iPhrase
** }
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" option. If the FTS5 table is created with either
** "detail=none" "content=" option (i.e. if it is a contentless table),
** then this API always iterates through an empty set (all calls to
** xPhraseFirstColumn() set iCol to -1).
**
** The information accessed using this API and its companion
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
** (or xInst/xInstCount). The chief advantage of this API is that it is
** significantly more efficient than those alternatives when used with
** "detail=column" tables.
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 1 */
int iVersion; /* Currently always set to 3 */
void *(*xUserData)(Fts5Context*);
@ -8162,8 +8404,11 @@ struct Fts5ExtensionApi {
int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
void *(*xGetAuxdata)(Fts5Context*, int bClear);
void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
};
/*

View File

@ -61,7 +61,7 @@ struct SQOuter;
#include "sqconfig.h"
#define SQUIRREL_VERSION _SC("Squirrel 3.1 RC1")
#define SQUIRREL_VERSION _SC("Squirrel 3.1 stable")
#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2015 Alberto Demichelis")
#define SQUIRREL_AUTHOR _SC("Alberto Demichelis")
#define SQUIRREL_VERSION_NUMBER 310
@ -249,6 +249,7 @@ SQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n);
SQUIRREL_API void sq_pushbool(HSQUIRRELVM v,SQBool b);
SQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);
SQUIRREL_API void sq_pushnull(HSQUIRRELVM v);
SQUIRREL_API void sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread);
SQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx);
SQUIRREL_API SQRESULT sq_typeof(HSQUIRRELVM v,SQInteger idx);
SQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx);
@ -267,6 +268,7 @@ SQUIRREL_API SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *
SQUIRREL_API SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag);
SQUIRREL_API SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag);
SQUIRREL_API void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook);
SQUIRREL_API SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx);
SQUIRREL_API SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize);
SQUIRREL_API SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi);
SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars);
@ -339,6 +341,8 @@ SQUIRREL_API SQInteger sq_objtointeger(const HSQOBJECT *o);
SQUIRREL_API SQFloat sq_objtofloat(const HSQOBJECT *o);
SQUIRREL_API SQUserPointer sq_objtouserpointer(const HSQOBJECT *o);
SQUIRREL_API SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag);
SQUIRREL_API SQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM v, const HSQOBJECT *po);
/*GC*/
SQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v);