diff --git a/demos/test/sandbox/sample.cpp b/demos/test/sandbox/sample.cpp index 914ef8ee..147c07a2 100644 --- a/demos/test/sandbox/sample.cpp +++ b/demos/test/sandbox/sample.cpp @@ -1,7 +1,7 @@ // // Lol Engine - Sandbox program // -// Copyright © 2005-2015 Sam Hocevar +// Copyright © 2005—2015 Sam Hocevar // // This program is free software. It comes without any warranty, to // the extent permitted by applicable law. You can redistribute it @@ -16,151 +16,17 @@ #include -#include "pegtl.hh" -namespace lol { namespace parser = pegtl; } - -#include "axe.h" -namespace lol { using namespace axe; } - using namespace lol; -// -// Parser tools for a simple calculator grammar with + - * / -// - -struct calculator -{ - void push(double d) { stack.Push(d); } - void pop() { printf("%f\n", stack.Pop()); } - - void mul() { auto x = stack.Pop(); stack.Push(stack.Pop() * x); } - void div() { auto x = stack.Pop(); stack.Push(stack.Pop() / x); } - void add() { auto x = stack.Pop(); stack.Push(stack.Pop() + x); } - void sub() { auto x = stack.Pop(); stack.Push(stack.Pop() - x); } - - array stack; -}; - -static void parse_pegtl(std::string const &str); -static void parse_axe(std::string const &str); - int main() { - std::string const str("42+2*(1-1+2+3-4*5)"); - - parse_axe(str); - parse_pegtl(str); - - return EXIT_SUCCESS; -} - -// -// PegTL -- a PEG parser -// - -namespace pegtl_parser -{ - using namespace lol::parser; - - #define ACTION(name, code) \ - struct name : action_base { \ - static void apply(std::string const &ctx, calculator &c) { \ - code \ - } \ - }; - - ACTION( do_number, c.push(atof(ctx.c_str())); ) - ACTION( do_op, - switch (ctx[0]) - { - case '*': c.mul(); break; - case '/': c.div(); break; - case '+': c.add(); break; - case '-': c.sub(); break; - } ) - ACTION( do_success, c.pop(); ) - - #undef ACTION - - // number <- + - struct number : ifapply, do_number> {}; - - // term <- number | "(" expr ")" - struct term : sor, struct expr, one<')'>>> {}; - - // factor <- term ( "*" term | "/" term ) * - struct factor : seq, term>, - seq, term>>, do_op>>> {}; - - // expr <- factor ( "+" factor | "-" factor ) * - struct expr : seq, factor>, - seq, factor>>, do_op>>> {}; - - // stmt <- expr - struct stmt : ifapply, do_success> {}; -}; - -static void parse_pegtl(std::string const & str) -{ - calculator c; - pegtl::basic_parse_string(str, c); -} - -// -// AXE -- a recursive descent parser (needs right-recursion) -// - -template -static void parse_axe_helper(IT i1, IT i2) -{ - calculator c; - double d; - - #define ACTION(code) e_ref([&](...) { code }) - - r_rule number, term, factor, factor_tail, expr, expr_tail, stmt; - - // number ::= - number = r_double(d) >> ACTION( c.push(d); ); - - // term ::= number | ( expr ) - term = number - | '(' & expr & ')'; - - // factor ::= term factor_tail - // factor_tail ::= * term factor_tail - // | / term factor_tail - // | ɛ - factor_tail = '*' & term >> ACTION( c.mul(); ) & factor_tail - | '/' & term >> ACTION( c.div(); ) & factor_tail - | r_empty(); - factor = term & factor_tail; - - // expr ::= factor expr_tail - // expr_tail ::= + factor expr_tail - // | - factor expr_tail - // | ɛ - expr_tail = '+' & factor >> ACTION( c.add(); ) & expr_tail - | '-' & factor >> ACTION( c.sub(); ) & expr_tail - | r_empty(); - expr = factor & expr_tail; - - // stmt ::= expr - // | - stmt = expr & r_end() >> ACTION( c.pop(); ) - | r_fail([](...) { printf("malformed expression\n"); }); - - #undef ACTION - - // Evaluate expression - stmt(i1, i2); -} - -static void parse_axe(std::string const &str) -{ - return parse_axe_helper(str.begin(), str.end()); + bigint<16> i; + bigint<16> x(2), y(12); + auto z = x + y; + printf("%d\n", (int)z); + + bigint<0> lol; + auto w = z + lol; + printf("%d\n", (int)w); } diff --git a/src/Makefile.am b/src/Makefile.am index 4e1990d9..f9a6d470 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,7 +42,7 @@ liblolcore_headers = \ lol/math/functions.h lol/math/vector.h lol/math/half.h lol/math/real.h \ lol/math/geometry.h lol/math/interp.h lol/math/rand.h lol/math/array2d.h \ lol/math/array3d.h lol/math/constants.h lol/math/matrix.h lol/math/ops.h \ - lol/math/transform.h lol/math/polynomial.h \ + lol/math/transform.h lol/math/polynomial.h lol/math/bigint.h \ lol/math/noise/gradient.h lol/math/noise/perlin.h \ lol/math/noise/simplex.h \ \ diff --git a/src/lol/math/all.h b/src/lol/math/all.h index e687dc9e..417d419c 100644 --- a/src/lol/math/all.h +++ b/src/lol/math/all.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/src/lol/math/bigint.h b/src/lol/math/bigint.h new file mode 100644 index 00000000..135f1937 --- /dev/null +++ b/src/lol/math/bigint.h @@ -0,0 +1,143 @@ +// +// Lol Engine +// +// Copyright © 2010—2015 Sam Hocevar +// +// This library is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#pragma once + +// +// The bigint class +// ---------------- +// + +#include + +#include + +namespace lol +{ + +/* This is OUR namespace. Don't let Windows headers fuck with it. */ +#undef min +#undef max + +/* Avoid issues with NaCl headers */ +#undef log2 + +/* + * A bigint stores its digits in an array of integers. The MSB of the + * integers are unused. The highest used bit is the sign bit. + * + * Digits are stored in little endian mode. + */ + +template +class bigint +{ + int const bits_per_digit = sizeof(T) * 8 - 1; + T const digit_mask = ~((T)1 << bits_per_digit); + +public: + inline bigint() + { + } + + explicit bigint(int32_t x) + { + /* FIXME: doesn’t work if sizeof(T) < sizeof(int32_t) */ + for (auto &digit : m_digits) + digit = x >= 0 ? (T)0 : digit_mask; + if (N > 0) + m_digits[0] = x & digit_mask; + } + + explicit bigint(uint32_t x) + { + /* FIXME: doesn’t work if sizeof(T) > sizeof(uint32_t) */ + for (auto &digit : m_digits) + digit = (T)0; + if (N > 0) + m_digits[0] = x & digit_mask; + if (N > 1) + m_digits[1] = x >> bits_per_digit; + } + + explicit inline operator uint32_t() const + { + /* FIXME: doesn’t work if sizeof(T) != sizeof(int32_t) */ + if (N < 1) + return 0; + if (N < 2) + return (uint32_t)(m_digits[0] + | ((m_digits[0] << 1) & ~digit_mask)); + + return (uint32_t)(m_digits[0] | (m_digits[1] << bits_per_digit)); + } + + inline operator int32_t() const + { + return (int32_t)(uint32_t)*this; + } + + /* + * bigint cast to bigint of different size: we copy all digits then + * pad the rest (if applicable) with zeroes or ones to extend the + * sign bit. + */ + template + explicit bigint(bigint const &x) + { + for (int i = 0; i < (N < M) ? N : M; ++i) + m_digits[i] = x.m_digits[i]; + + if (N > M) + { + T padding = x.is_negative() ? digit_mask : (T)0; + for (int i = M; i < N; ++i) + m_digits[i] = padding; + } + } + + /* + * bigint addition: we add the digits one-to-one, carrying overflows, + * and replace digits with padding if one of the two operands is + * shorter. + */ + template + bigint<(N > M) ? N : M, T> operator +(bigint const &x) const + { + bigint<(N > M) ? N : M, T> ret; + T padding = is_negative() ? digit_mask : (T)0; + T x_padding = x.is_negative() ? digit_mask : (T)0; + T carry(0); + for (int i = 0; i < (N > M) ? N : M; ++i) + { + T digit = (i < N ? m_digits[i] : padding) + + (i < M ? x.m_digits[i] : x_padding) + + carry; + ret.m_digits[i] = digit & digit_mask; + carry = (digit & ~digit_mask) ? T(1) : T(0); + } + return ret; + } + +private: + inline bool is_negative() const + { + if (N < 1) + return false; + return (m_digits[N - 1] & ((T)1 << (bits_per_digit - 1))) != 0; + } + + T m_digits[N]; +}; + +} /* namespace lol */ + diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 28263dc3..5c3744ff 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -287,6 +287,7 @@ + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index d0059269..1e0f23e2 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -417,6 +417,9 @@ lol\math + + lol\math + lol\math diff --git a/src/t/Makefile.am b/src/t/Makefile.am index 4ef58988..60c1109f 100644 --- a/src/t/Makefile.am +++ b/src/t/Makefile.am @@ -20,7 +20,8 @@ test_math_SOURCES = test-common.cpp \ math/array2d.cpp math/array3d.cpp math/arraynd.cpp math/box.cpp \ math/cmplx.cpp math/half.cpp math/interp.cpp math/matrix.cpp \ math/quat.cpp math/rand.cpp math/real.cpp math/rotation.cpp \ - math/trig.cpp math/vector.cpp math/polynomial.cpp math/noise/simplex.cpp + math/trig.cpp math/vector.cpp math/polynomial.cpp math/noise/simplex.cpp \ + math/bigint.cpp test_math_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tools/lolunit test_math_DEPENDENCIES = @LOL_DEPS@ diff --git a/src/t/math/bigint.cpp b/src/t/math/bigint.cpp new file mode 100644 index 00000000..4e8d00dd --- /dev/null +++ b/src/t/math/bigint.cpp @@ -0,0 +1,60 @@ +// +// Lol Engine +// +// Copyright © 2010—2015 Sam Hocevar +// +// This program is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#include + +#include + +#include + +namespace lol +{ + +lolunit_declare_fixture(bigint_test) +{ + lolunit_declare_test(declaration) + { + bigint<> a; + bigint<0> b; + bigint<32> c; + } + + lolunit_declare_test(int32_cast) + { + bigint<> a(0), b(1), c(-1); + + lolunit_assert_equal((int32_t)a, 0); + lolunit_assert_equal((int32_t)b, 1); + lolunit_assert_equal((int32_t)c, -1); + } + + lolunit_declare_test(uint32_cast) + { + bigint<> a(0), b(1), c(~(uint32_t)0); + + lolunit_assert_equal((uint32_t)a, 0); + lolunit_assert_equal((uint32_t)b, 1); + lolunit_assert_equal((uint32_t)c, ~(uint32_t)0); + } + + lolunit_declare_test(empty_bigint_is_zero) + { + bigint<0> a, b(1), c(-1); + + lolunit_assert_equal((int)a, 0); + lolunit_assert_equal((int)b, 0); + lolunit_assert_equal((int)c, 0); + } +}; + +} /* namespace lol */ + diff --git a/src/t/test-math.vcxproj b/src/t/test-math.vcxproj index c99e0ff6..88f538b5 100644 --- a/src/t/test-math.vcxproj +++ b/src/t/test-math.vcxproj @@ -40,6 +40,7 @@ +