diff options
Diffstat (limited to 'vendor/CppQuickCheck-2018-03-28/include/cppqc/Arbitrary.h')
-rw-r--r-- | vendor/CppQuickCheck-2018-03-28/include/cppqc/Arbitrary.h | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc/Arbitrary.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Arbitrary.h new file mode 100644 index 00000000..ecfc56c1 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Arbitrary.h @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDERS OR CONTRIBUTORS 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. + */ + +#ifndef CPPQC_ARBITRARY_H +#define CPPQC_ARBITRARY_H + +#include "Generator.h" + +#include <limits> + +#include <boost/random/uniform_int.hpp> +#include <boost/random/uniform_smallint.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/random/uniform_01.hpp> +#include <boost/random/poisson_distribution.hpp> +#include <boost/random/variate_generator.hpp> + +namespace cppqc { + +// default generators + +template<class Integral> +Integral arbitrarySizedIntegral(RngEngine &rng, std::size_t size) +{ + boost::uniform_int<Integral> dist(std::numeric_limits<Integral>::is_signed ? + -Integral(size) : Integral(size), + Integral(size)); + return dist(rng); +} + +template<class Integral> +Integral arbitraryBoundedIntegral(RngEngine &rng, std::size_t /*size*/) +{ + boost::uniform_int<Integral> dist(std::numeric_limits<Integral>::min(), + std::numeric_limits<Integral>::max()); + return dist(rng); +} + +template<class Integral> +Integral arbitrarySizedBoundedIntegral(RngEngine &rng, std::size_t size) +{ + boost::poisson_distribution<Integral> dist(size == 0 ? 1 : size); + boost::variate_generator<RngEngine&, boost::uniform_01<> > gen(rng, boost::uniform_01<>()); + Integral r = dist(gen); + if (std::numeric_limits<Integral>::is_signed) { + if (boost::uniform_smallint<int>(0, 1)(rng)) + r = -r; + } + return r; +} + +template<class Real> +Real arbitrarySizedReal(RngEngine &rng, std::size_t size) +{ + boost::uniform_real<Real> dist(-Real(size + 1.0), Real(size + 1.0)); + return dist(rng); +} + +// default shrinkers + +template<class T> +std::vector<T> shrinkNothing(const T &) +{ + return std::vector<T>(); +} + +template<class Integral> +std::vector<Integral> shrinkIntegral(Integral x) +{ + std::vector<Integral> ret; + if (std::numeric_limits<Integral>::is_signed && x < 0) { + if (x == std::numeric_limits<Integral>::min()) { + ret.push_back(std::numeric_limits<Integral>::max()); + } else { + assert(-x > 0); + ret.push_back(-x); + } + } + + for (Integral n = x; n != 0; n /= 2) + ret.push_back(x - n); + return ret; +} + +template<class Real> +std::vector<Real> shrinkReal(Real x) +{ + std::vector<Real> ret; + if (x == 0) + return ret; + if (x < 0) + ret.push_back(-x); + ret.push_back(Real(0)); + + if (std::isnan(x) && std::abs(x) >= 2) { + if (std::abs(x) < 1e100) { + ret.push_back(x / Real(2)); + } else { + // special case: reduce faster if the numbers are huge + // (Note: Maybe there is a better heuristic. Looks quite crude.) + ret.push_back(x / Real(1e20)); + } + } + return ret; +} + + +template<class T> +struct Arbitrary +{ + typedef boost::function<T (RngEngine &, std::size_t)> unGenType; + typedef boost::function<std::vector<T> (T)> shrinkType; + + static const unGenType unGen; + static const shrinkType shrink; +}; + +/* + * specialize ArbitraryImpl and implement the members: + * static const Arbitrary<T>::unGenType unGen; + * static const Arbitrary<T>::shrinkType shrink; + */ +template<class T> +struct ArbitraryImpl +{ + // no default implementation - users must specialize ArbitraryImpl + // and give an implementation of unGen and shrink. If they do not + // and they try to use Arbitrary<TheirClass>, a compile error will result. +}; + +// Note: The call is wrapped in a function to avoid issues +// with static ordering when ArbitraryImpl is defined +// in another compilation unit. Do not simplify it +// by replacing it with an assignment. +template<class T> +const typename Arbitrary<T>::unGenType Arbitrary<T>::unGen = [](RngEngine &rng, + std::size_t size) { + return ArbitraryImpl<T>::unGen(rng, size); +}; + +// (function call is needed: see above) +template<class T> +const typename Arbitrary<T>::shrinkType Arbitrary<T>::shrink = [](const T &v) { + return ArbitraryImpl<T>::shrink(v); +}; + +// included specializations + +inline bool arbitraryBool(RngEngine &rng, std::size_t /*size*/) +{ + if (boost::uniform_smallint<int>(0, 1)(rng)) + return true; + return false; +} +inline std::vector<bool> shrinkBool(bool x) +{ + std::vector<bool> ret; + if (x) ret.push_back(false); + return ret; +} +template<> +struct ArbitraryImpl<bool> +{ + static const Arbitrary<bool>::unGenType unGen; + static const Arbitrary<bool>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed char> +{ + static const Arbitrary<signed char>::unGenType unGen; + static const Arbitrary<signed char>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned char> +{ + static const Arbitrary<unsigned char>::unGenType unGen; + static const Arbitrary<unsigned char>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed short> +{ + static const Arbitrary<signed short>::unGenType unGen; + static const Arbitrary<signed short>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned short> +{ + static const Arbitrary<unsigned short>::unGenType unGen; + static const Arbitrary<unsigned short>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed int> +{ + static const Arbitrary<signed int>::unGenType unGen; + static const Arbitrary<signed int>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned int> +{ + static const Arbitrary<unsigned int>::unGenType unGen; + static const Arbitrary<unsigned int>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed long> +{ + static const Arbitrary<signed long>::unGenType unGen; + static const Arbitrary<signed long>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned long> +{ + static const Arbitrary<unsigned long>::unGenType unGen; + static const Arbitrary<unsigned long>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed long long> +{ + static const Arbitrary<signed long long>::unGenType unGen; + static const Arbitrary<signed long long>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned long long> +{ + static const Arbitrary<unsigned long long>::unGenType unGen; + static const Arbitrary<unsigned long long>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<float> +{ + static const Arbitrary<float>::unGenType unGen; + static const Arbitrary<float>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<double> +{ + static const Arbitrary<double>::unGenType unGen; + static const Arbitrary<double>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<long double> +{ + static const Arbitrary<long double>::unGenType unGen; + static const Arbitrary<long double>::shrinkType shrink; +}; + +inline char arbitraryChar(RngEngine &rng, std::size_t) +{ + boost::uniform_int<char> dist(0x20, 0x7f); + return dist(rng); +} +inline std::vector<char> shrinkChar(char c) +{ + const char possShrinks[] = {'a', 'b', 'c', 'A', 'B', 'C', '1', '2', '3', + ' ', '\n', '\0'}; + std::vector<char> ret; + for (auto & possShrink : possShrinks) { + if (possShrink < c) + ret.push_back(possShrink); + } + if (isupper(c) && + std::find(possShrinks, possShrinks + sizeof(possShrinks), + tolower(c)) != possShrinks + sizeof(possShrinks)) + ret.push_back(tolower(c)); + return ret; +} +template<> +struct ArbitraryImpl<char> +{ + static const Arbitrary<char>::unGenType unGen; + static const Arbitrary<char>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<wchar_t> +{ + static const Arbitrary<wchar_t>::unGenType unGen; + static const Arbitrary<wchar_t>::shrinkType shrink; +}; + +template<class String> +String arbitraryString(RngEngine &rng, std::size_t size) +{ + boost::uniform_int<std::size_t> dist(0, size); + std::size_t n = dist(rng); + String ret; + ret.reserve(n); + while (n-- > 0) + ret.push_back(Arbitrary<typename String::value_type>::unGen(rng, size)); + return ret; +} +template<class String> +std::vector<String> shrinkString(const String &x) +{ + std::vector<String> ret; + ret.reserve(x.size()); + for (auto it = x.begin(); it != x.end(); ++it) { + ret.push_back(String()); + ret.back().reserve(x.size() - 1); + ret.back().insert(ret.back().end(), x.begin(), it); + ret.back().insert(ret.back().end(), it + 1, x.end()); + } + return ret; +} +template<class CharT, class Traits, class Alloc> +struct ArbitraryImpl<std::basic_string<CharT, Traits, Alloc> > +{ + static const typename + Arbitrary<std::basic_string<CharT, Traits, Alloc> >::unGenType unGen; + static const typename + Arbitrary<std::basic_string<CharT, Traits, Alloc> >::shrinkType shrink; +}; +template<class CharT, class Traits, class Alloc> +const typename Arbitrary<std::basic_string<CharT, Traits, Alloc> >::unGenType +ArbitraryImpl<std::basic_string<CharT, Traits, Alloc> >::unGen = +arbitraryString<std::basic_string<CharT, Traits, Alloc> >; +template<class CharT, class Traits, class Alloc> +const typename Arbitrary<std::basic_string<CharT, Traits, Alloc> >::shrinkType +ArbitraryImpl<std::basic_string<CharT, Traits, Alloc> >::shrink = +shrinkString<std::basic_string<CharT, Traits, Alloc> >; + +template<class PairType> +PairType arbitraryPair(RngEngine &rng, std::size_t size) +{ + return PairType(Arbitrary<typename PairType::first_type>::unGen(rng, size), + Arbitrary<typename PairType::second_type>::unGen(rng, size)); +} +template<class PairType> +std::vector<PairType> shrinkPair(const PairType &x) +{ + typedef typename PairType::first_type FirstType; + typedef typename PairType::second_type SecondType; + std::vector<FirstType> shrinks1 = Arbitrary<FirstType>::shrink(x.first); + std::vector<SecondType> shrinks2 = Arbitrary<SecondType>::shrink(x.second); + std::vector<PairType> ret; + ret.reserve(shrinks1.size() + shrinks2.size()); + for (auto it = shrinks1.begin(); it != shrinks1.end(); ++it) { + ret.push_back(PairType(*it, x.second)); + } + for (auto it = shrinks2.begin(); it != shrinks2.end(); ++it) { + ret.push_back(PairType(x.first, *it)); + } + return ret; +} +template<class T1, class T2> +struct ArbitraryImpl<std::pair<T1, T2> > +{ + static const typename Arbitrary<std::pair<T1, T2> >::unGenType unGen; + static const typename Arbitrary<std::pair<T1, T2> >::shrinkType shrink; +}; +template<class T1, class T2> +const typename Arbitrary<std::pair<T1, T2> >::unGenType +ArbitraryImpl<std::pair<T1, T2> >::unGen = arbitraryPair<std::pair<T1, T2> >; +template<class T1, class T2> +const typename Arbitrary<std::pair<T1, T2> >::shrinkType +ArbitraryImpl<std::pair<T1, T2> >::shrink = shrinkPair<std::pair<T1, T2> >; + +template<typename T> +struct ArbitraryImpl<std::vector<T>> +{ + static const typename Arbitrary<std::vector<T>>::unGenType unGen; + static const typename Arbitrary<std::vector<T>>::shrinkType shrink; +}; + +template <typename T> +const typename Arbitrary<std::vector<T>>::unGenType + ArbitraryImpl<std::vector<T>>::unGen = [](RngEngine &rng, + std::size_t size) { + const auto& vectorGenerator = listOf<T>(); + return vectorGenerator.unGen(rng, size); +}; + +template <typename T> +const typename Arbitrary<std::vector<T>>::shrinkType + ArbitraryImpl<std::vector<T>>::shrink = [](const std::vector<T> &v) { + + const auto& vectorGenerator = listOf<T>(); + return vectorGenerator.shrink(v); +}; + + +template<typename T, std::size_t N> +struct ArbitraryImpl<std::array<T, N>> +{ + static const typename Arbitrary<std::array<T, N>>::unGenType unGen; + static const typename Arbitrary<std::array<T, N>>::shrinkType shrink; +}; + +/// Note: N is the fixed size of the array. +/// It differs from the "size" param in the "unGen" function: +/// +/// If "size" is increased, the output array will still contain +/// N elements, but each element will, in general, be more complex. +template <typename T, std::size_t N> +const typename Arbitrary<std::array<T, N>>::unGenType + ArbitraryImpl<std::array<T, N>>::unGen = [](RngEngine &rng, + std::size_t size) { + const auto& arrayGenerator = arrayOf<T, N>(); + return arrayGenerator.unGen(rng, size); +}; + +template <typename T, std::size_t N> +const typename Arbitrary<std::array<T, N>>::shrinkType + ArbitraryImpl<std::array<T, N>>::shrink = [](const std::array<T, N> &arr) { + + const auto& arrayGenerator = arrayOf<T, N>(); + return arrayGenerator.shrink(arr); +}; + +} + +#endif |