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:
@ -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
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
13
include/RandomLib/Config.h
Normal file
13
include/RandomLib/Config.h
Normal 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
|
432
include/RandomLib/DiscreteNormal.hpp
Normal file
432
include/RandomLib/DiscreteNormal.hpp
Normal 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 σ and μ 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 σ = 7 and μ = 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
|
||||
* = ±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 ≥ 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, ⌈σ⌉). 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 ≥ 1
|
||||
* (this is counted with the next larger value of \e k) or if \e x = 0, \e k
|
||||
* = 0, and \e s = −1 (to avoid double counting the origin). If \e x
|
||||
* is accepted (in Step 4 of the ExactNormal algorithm), then return \e i.
|
||||
*
|
||||
* When σ and μ 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 σ and μ (roughly comparable to
|
||||
* the time it takes to generate one sample),
|
||||
* - only about 5–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>σ, for large σ,
|
||||
* where the constant is about 31.
|
||||
* .
|
||||
* The possible drawbacks of this method are:
|
||||
* - σ and μ 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, μ = 0, and 10<sup>8</sup>
|
||||
* samples (time = time per sample, including setup time, rv = mean number of
|
||||
* random variables per sample)
|
||||
* - σ = 10, time = 219 ns, rv = 17.52
|
||||
* - σ = 32, time = 223 ns, rv = 17.82
|
||||
* - σ = 1000, time = 225 ns, rv = 17.95
|
||||
* - σ = 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 σ.
|
||||
* @param[in] sigma_den the denominator of σ (default 1).
|
||||
* @param[in] mu_num the numerator of μ (default 0).
|
||||
* @param[in] mu_den the denominator of μ (default 1).
|
||||
*
|
||||
* The constructor creates a DiscreteNormal objects for sampling with
|
||||
* specific values of σ and μ. This may throw an exception if the
|
||||
* parameters are such that overflow is possible. Internally σ and
|
||||
* μ 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 − 2) / \e m,
|
||||
* - 0 (succeed with probability x) with prob 1 / \e m,
|
||||
* - −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(−1/2).
|
||||
**********************************************************************/
|
||||
template<class Random> bool ExpProbH(Random& r) const;
|
||||
|
||||
/**
|
||||
* Return true with probability exp(−<i>n</i>/2).
|
||||
**********************************************************************/
|
||||
template<class Random> bool ExpProb(Random& r, int n) const;
|
||||
|
||||
/**
|
||||
* Return \e n with probability exp(−<i>n</i>/2)
|
||||
* (1−exp(−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
|
328
include/RandomLib/DiscreteNormalAlt.hpp
Normal file
328
include/RandomLib/DiscreteNormalAlt.hpp
Normal 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 σ and μ 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 σ = 7 and μ = 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
|
||||
* σ consuming constant + log<sub>2</sub>σ 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>σ 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 σ is a power of 2; the "max" results apply when σ is
|
||||
* slightly more than a power of two; the "mean" results are averaged over
|
||||
* σ. The toll is the excess number of bits over the entropy of the
|
||||
* distribution, which is log<sub>2</sub>(2π\e e)/2 +
|
||||
* log<sub>2</sub>σ (for σ 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>σ
|
||||
* \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 σ.
|
||||
* @param[in] sigma_den the denominator of σ (default 1).
|
||||
* @param[in] mu_num the numerator of μ (default 0).
|
||||
* @param[in] mu_den the denominator of μ (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 − 2) / \e m,
|
||||
* - 0 (succeed with probability x) with prob 1 / \e m,
|
||||
* - −1 (fail unconditionally) with prob 1 / \e m.
|
||||
**********************************************************************/
|
||||
template<class Random> static int Choose(Random& r, int m);
|
||||
|
||||
/**
|
||||
* Return true with probability exp(−1/2).
|
||||
**********************************************************************/
|
||||
template<class Random> bool ExpProbH(Random& r) const;
|
||||
|
||||
/**
|
||||
* Return true with probability exp(−<i>n</i>/2).
|
||||
**********************************************************************/
|
||||
template<class Random> bool ExpProb(Random& r, int n) const;
|
||||
|
||||
/**
|
||||
* Return \e n with probability exp(−<i>n</i>/2)
|
||||
* (1−exp(−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
|
241
include/RandomLib/ExactExponential.hpp
Normal file
241
include/RandomLib/ExactExponential.hpp
Normal 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 ≥ 0 from exp(−\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 − exp(-1)) = 4.30 random
|
||||
* numbers on average. (Von Neumann incorrectly states that the method takes
|
||||
* (1 + exp(1))/(1 − exp(-1)) = 5.88 random numbers on average.)
|
||||
* Because of the finite precision of Random::Fixed(), the code snippet above
|
||||
* only approximates exp(−\e x). Instead, it returns \e x with
|
||||
* probability \e h(1 − \e h)<sup><i>x</i>/<i>h</i></sup> for \e x = \e
|
||||
* ih, \e h = 2<sup>−53</sup>, and integer \e i ≥ 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 ≤
|
||||
* 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−\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(−\e
|
||||
* x) for \e x ≥ 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) −
|
||||
* (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
|
||||
* − exp(−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(−\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
|
417
include/RandomLib/ExactNormal.hpp
Normal file
417
include/RandomLib/ExactNormal.hpp
Normal 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(−<i>x</i><sup>2</sup>/2) / sqrt(2π). 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 ≥ 0 with probability
|
||||
* exp(−<i>k</i>/2) (1−exp(−1/2)).
|
||||
* -# Accept with probability
|
||||
* exp(− \e k (\e k − 1) / 2); otherwise, reject and start
|
||||
* over at step 1.
|
||||
* -# Sample a random number \e x uniformly from [0,1).
|
||||
* -# Accept with probability exp(− \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(−1/2)) increment \e k by 1.
|
||||
* - Step 2:
|
||||
* - \e n = \e k (\e k − 1) / 2;
|
||||
* - while (\e n > 0)
|
||||
* { if (!ExpProb(−1/2)) go to step 1; decrement \e n by 1; }
|
||||
* - Step 4:
|
||||
* - repeat \e k + 1 times:
|
||||
* if (!ExpProb(− \e x (\e x + 2\e k) / (2\e k + 2))) go to step 1.
|
||||
* .
|
||||
* Here, ExpProb(−\e p) returns true with probability exp(−\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> < (\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> < (\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) − (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(−1/2). For \e bits = 1, this
|
||||
* consumes, on average, \e t = 2.846 random digits. We have \e t = \e a
|
||||
* (1−exp(−1/2)) + \e b exp(−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(−<i>n</i>/2). For \e bits = 1,
|
||||
* this consumes, on average, \e t
|
||||
* (1−exp(−<i>n</i>/2))/(1−exp(−1/2)) random
|
||||
* digits. A true result uses \e n \e b random digits. A false result
|
||||
* uses \e a + \e b [exp(−1/2)/(1−exp(−1/2)) −
|
||||
* <i>n</i> exp(−<i>n</i>/2)/(1−exp(−<i>n</i>/2))] random
|
||||
* digits.
|
||||
**********************************************************************/
|
||||
template<class Random> bool ExpProb(Random& r, unsigned n) const;
|
||||
|
||||
/**
|
||||
* Return \e n with probability exp(−<i>n</i>/2)
|
||||
* (1−exp(−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 − (\e b − \e a) exp(−1/2))/(1 −
|
||||
* exp(−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),
|
||||
* - −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
|
100
include/RandomLib/ExactPower.hpp
Normal file
100
include/RandomLib/ExactPower.hpp
Normal 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 ≥ 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 ≥ 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
|
69
include/RandomLib/ExponentialDistribution.hpp
Normal file
69
include/RandomLib/ExponentialDistribution.hpp
Normal 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(−<i>x</i>/μ) for \e x ≥ 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 μ. This uses Random::FloatU() which avoids taking log(0) and
|
||||
* allows rare large values to be returned. If μ = 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
|
166
include/RandomLib/ExponentialProb.hpp
Normal file
166
include/RandomLib/ExponentialProb.hpp
Normal 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(−\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 [−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(−\e p). Returns false if \e p
|
||||
* ≤ 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 − exp(−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(−\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
|
67
include/RandomLib/InverseEProb.hpp
Normal file
67
include/RandomLib/InverseEProb.hpp
Normal 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(−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
|
150
include/RandomLib/InversePiProb.hpp
Normal file
150
include/RandomLib/InversePiProb.hpp
Normal file
@ -0,0 +1,150 @@
|
||||
/**
|
||||
* \file InversePiProb.hpp
|
||||
* \brief Header for InversePiProb
|
||||
*
|
||||
* Return true with probabililty 1/π.
|
||||
*
|
||||
* 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/π.
|
||||
*
|
||||
* InversePiProb p; p(Random& r) returns true with prob 1/π 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/π given by Eq. (28) of<br>
|
||||
* - S. Ramanujan,<br>
|
||||
* Modular Equations and Approximations to π,<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> = ⌊<i>h</i><sub>1</sub>/2⌋ +
|
||||
* ⌊<i>h</i><sub>2</sub>/2⌋ +
|
||||
* mod(⌊(<i>h</i><sub>3</sub> − 1)/3⌋, 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> →
|
||||
* <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> ≥ 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/π.
|
||||
*
|
||||
* @tparam Random the type of the random generator.
|
||||
* @param[in,out] r a random generator.
|
||||
* @return true with probability 1/π.
|
||||
**********************************************************************/
|
||||
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
|
84
include/RandomLib/LeadingZeros.hpp
Normal file
84
include/RandomLib/LeadingZeros.hpp
Normal 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
|
92
include/RandomLib/MPFRExponential.hpp
Normal file
92
include/RandomLib/MPFRExponential.hpp
Normal 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 (± 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
|
123
include/RandomLib/MPFRExponentialL.hpp
Normal file
123
include/RandomLib/MPFRExponentialL.hpp
Normal 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 (± 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
|
144
include/RandomLib/MPFRNormal.hpp
Normal file
144
include/RandomLib/MPFRNormal.hpp
Normal 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 (±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
|
138
include/RandomLib/MPFRNormalK.hpp
Normal file
138
include/RandomLib/MPFRNormalK.hpp
Normal 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 (±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
|
255
include/RandomLib/MPFRNormalR.hpp
Normal file
255
include/RandomLib/MPFRNormalR.hpp
Normal 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 (±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
|
383
include/RandomLib/MPFRRandom.hpp
Normal file
383
include/RandomLib/MPFRRandom.hpp
Normal 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 ≥ 0 and 0 ≤ \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>−<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 (± 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 (± 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 (± 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
|
72
include/RandomLib/MPFRUniform.hpp
Normal file
72
include/RandomLib/MPFRUniform.hpp
Normal 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 (± 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
|
114
include/RandomLib/NormalDistribution.hpp
Normal file
114
include/RandomLib/NormalDistribution.hpp
Normal 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
|
||||
* μ and standard deviation σ.
|
||||
*
|
||||
* For μ = 0 and σ = 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
|
141
include/RandomLib/Random.hpp
Normal file
141
include/RandomLib/Random.hpp
Normal 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
|
384
include/RandomLib/RandomAlgorithm.hpp
Normal file
384
include/RandomLib/RandomAlgorithm.hpp
Normal 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> − 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 − \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> − 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 − 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> − 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
|
1301
include/RandomLib/RandomCanonical.hpp
Normal file
1301
include/RandomLib/RandomCanonical.hpp
Normal file
File diff suppressed because it is too large
Load Diff
640
include/RandomLib/RandomEngine.hpp
Normal file
640
include/RandomLib/RandomEngine.hpp
Normal 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> − 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 − 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
|
258
include/RandomLib/RandomMixer.hpp
Normal file
258
include/RandomLib/RandomMixer.hpp
Normal 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
|
472
include/RandomLib/RandomNumber.hpp
Normal file
472
include/RandomLib/RandomNumber.hpp
Normal 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
|
||||
* ∑<sub><i>k</i>=1</sub><sup><i>m</i></sup>
|
||||
* <i>f</i><sub><i>k</i>−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 (−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 (± 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 < \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 < \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 > 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 > 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 < <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 > 0).
|
||||
* @return true if *this < <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 > 0).
|
||||
* @param[in] q the denominator of the fraction (require \e q > 0).
|
||||
* @param[in,out] j the increment for the numerator.
|
||||
* @return true if *this < (<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
|
77
include/RandomLib/RandomPower2.hpp
Normal file
77
include/RandomLib/RandomPower2.hpp
Normal 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
|
251
include/RandomLib/RandomSeed.hpp
Normal file
251
include/RandomLib/RandomSeed.hpp
Normal 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
|
335
include/RandomLib/RandomSelect.hpp
Normal file
335
include/RandomLib/RandomSelect.hpp
Normal 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) ≥ digits(\e WeightType)
|
||||
* - \e WeightType integer, \e NumericType real
|
||||
* - \e WeightType real, \e NumericType real with digits(\e NumericType)
|
||||
* ≥ 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
|
137
include/RandomLib/RandomType.hpp
Normal file
137
include/RandomLib/RandomType.hpp
Normal 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
|
253
include/RandomLib/UniformInteger.hpp
Normal file
253
include/RandomLib/UniformInteger.hpp
Normal 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>σ. If Lumbroso's algorithm
|
||||
* for sampling in [0,\e m) were used the log<sub>2</sub>σ 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 − 1)/(\e b − 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 − 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()] → [−Max(), −Min()].
|
||||
**********************************************************************/
|
||||
void Negate() { _a = -Max(); }
|
||||
/**
|
||||
* Add a constant to the range
|
||||
*
|
||||
* @param[in] c the constant to be added.
|
||||
*
|
||||
* [Min(), Max()] → [Min() + \e c, Max() + \e c].
|
||||
**********************************************************************/
|
||||
void Add(IntType c) { _a += c; }
|
||||
/**
|
||||
* Compare with a fraction, *this < <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 > 0).
|
||||
* @return true if *this < <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 ≤ <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 > 0).
|
||||
* @return true if *this ≤ <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 > <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 > 0).
|
||||
* @return true if *this > <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 ≥ <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 > 0).
|
||||
* @return true if *this ≥ <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
|
@ -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
|
||||
|
3127
include/format.h
3127
include/format.h
File diff suppressed because it is too large
Load Diff
@ -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 */
|
@ -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 */
|
@ -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
1400
include/pugixml.hpp
1400
include/pugixml.hpp
File diff suppressed because it is too large
Load Diff
@ -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
@ -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_
|
@ -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_
|
@ -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__
|
@ -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__
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_
|
@ -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_ ]
|
@ -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
@ -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_
|
@ -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
@ -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_
|
@ -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_
|
@ -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);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user