aboutsummaryrefslogtreecommitdiff
path: root/libphobos/src/std/internal
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2019-06-18 20:42:10 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2021-11-30 16:53:28 +0100
commit5fee5ec362f7a243f459e6378fd49dfc89dc9fb5 (patch)
tree61d1bdbca854a903c0860406f457f06b2040be7a /libphobos/src/std/internal
parentb3f60112edcb85b459e60f66c44a55138b1cef49 (diff)
downloadgcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.zip
gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.tar.gz
gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.tar.bz2
d: Import dmd b8384668f, druntime e6caaab9, phobos 5ab9ad256 (v2.098.0-beta.1)
The D front-end is now itself written in D, in order to build GDC, you will need a working GDC compiler (GCC version 9.1 or later). GCC changes: - Add support for bootstrapping the D front-end. These add the required components in order to have a D front-end written in D itself. Because the compiler front-end only depends on the core runtime modules, only libdruntime is built for the bootstrap stages. D front-end changes: - Import dmd v2.098.0-beta.1. Druntime changes: - Import druntime v2.098.0-beta.1. Phobos changes: - Import phobos v2.098.0-beta.1. The jump from v2.076.1 to v2.098.0 covers nearly 4 years worth of development on the D programming language and run-time libraries. ChangeLog: * Makefile.def: Add bootstrap to libbacktrace, libphobos, zlib, and libatomic. * Makefile.in: Regenerate. * Makefile.tpl (POSTSTAGE1_HOST_EXPORTS): Fix command for GDC. (STAGE1_CONFIGURE_FLAGS): Add --with-libphobos-druntime-only if target-libphobos-bootstrap. (STAGE2_CONFIGURE_FLAGS): Likewise. * configure: Regenerate. * configure.ac: Add support for bootstrapping D front-end. config/ChangeLog: * acx.m4 (ACX_PROG_GDC): New m4 function. gcc/ChangeLog: * Makefile.in (GDC): New variable. (GDCFLAGS): New variable. * configure: Regenerate. * configure.ac: Add call to ACX_PROG_GDC. Substitute GDCFLAGS. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd b8384668f. * Make-lang.in (d-warn): Use strict warnings. (DMD_WARN_CXXFLAGS): Remove. (DMD_COMPILE): Remove. (CHECKING_DFLAGS): Define. (WARN_DFLAGS): Define. (ALL_DFLAGS): Define. (DCOMPILE.base): Define. (DCOMPILE): Define. (DPOSTCOMPILE): Define. (DLINKER): Define. (DLLINKER): Define. (D_FRONTEND_OBJS): Add new dmd front-end objects. (D_GENERATED_SRCS): Remove. (D_GENERATED_OBJS): Remove. (D_ALL_OBJS): Remove D_GENERATED_OBJS. (d21$(exeext)): Build using DLLINKER and -static-libphobos. (d.tags): Remove dmd/*.c and dmd/root/*.c. (d.mostlyclean): Remove D_GENERATED_SRCS, d/idgen$(build_exeext), d/impcnvgen$(build_exeext). (D_INCLUDES): Include $(srcdir)/d/dmd/res. (CFLAGS-d/id.o): Remove. (CFLAGS-d/impcnvtab.o): Remove. (d/%.o): Build using DCOMPILE and DPOSTCOMPILE. Update dependencies from d/dmd/%.c to d/dmd/%.d. (d/idgen$(build_exeext)): Remove. (d/impcnvgen$(build_exeext)): Remove. (d/id.c): Remove. (d/id.h): Remove. (d/impcnvtab.c): Remove. (d/%.dmdgen.o): Remove. (D_SYSTEM_H): Remove. (d/idgen.dmdgen.o): Remove. (d/impcnvgen.dmdgen.o): Remove. * config-lang.in (boot_language): New variable. * d-attribs.cc: Include dmd/expression.h. * d-builtins.cc: Include d-frontend.h. (build_frontend_type): Update for new front-end interface. (d_eval_constant_expression): Likewise. (d_build_builtins_module): Likewise. (maybe_set_builtin_1): Likewise. (d_build_d_type_nodes): Likewise. * d-codegen.cc (d_decl_context): Likewise. (declaration_reference_p): Likewise. (declaration_type): Likewise. (parameter_reference_p): Likewise. (parameter_type): Likewise. (get_array_length): Likewise. (build_delegate_cst): Likewise. (build_typeof_null_value): Likewise. (identity_compare_p): Likewise. (lower_struct_comparison): Likewise. (build_filename_from_loc): Likewise. (build_assert_call): Remove LIBCALL_SWITCH_ERROR. (build_bounds_index_condition): Call LIBCALL_ARRAYBOUNDS_INDEXP on bounds error. (build_bounds_slice_condition): Call LIBCALL_ARRAYBOUNDS_SLICEP on bounds error. (array_bounds_check): Update for new front-end interface. (checkaction_trap_p): Handle CHECKACTION_context. (get_function_type): Update for new front-end interface. (d_build_call): Likewise. * d-compiler.cc: Remove include of dmd/scope.h. (Compiler::genCmain): Remove. (Compiler::paintAsType): Update for new front-end interface. (Compiler::onParseModule): Likewise. * d-convert.cc (convert_expr): Remove call to LIBCALL_ARRAYCAST. (convert_for_rvalue): Update for new front-end interface. (convert_for_assignment): Likewise. (convert_for_condition): Likewise. (d_array_convert): Likewise. * d-diagnostic.cc (error): Remove. (errorSupplemental): Remove. (warning): Remove. (warningSupplemental): Remove. (deprecation): Remove. (deprecationSupplemental): Remove. (message): Remove. (vtip): New. * d-frontend.cc (global): Remove. (Global::_init): Remove. (Global::startGagging): Remove. (Global::endGagging): Remove. (Global::increaseErrorCount): Remove. (Loc::Loc): Remove. (Loc::toChars): Remove. (Loc::equals): Remove. (isBuiltin): Update for new front-end interface. (eval_builtin): Likewise. (getTypeInfoType): Likewise. (inlineCopy): Remove. * d-incpath.cc: Include d-frontend.h. (add_globalpaths): Call d_gc_malloc to allocate Strings. (add_filepaths): Likewise. * d-lang.cc: Include dmd/id.h, dmd/root/file.h, d-frontend.h. Remove include of dmd/mars.h, id.h. (entrypoint_module): Remove. (entrypoint_root_module): Remove. (deps_write_string): Update for new front-end interface. (deps_write): Likewise. (d_init_options): Call rt_init. Remove setting global params that are default initialized by the front-end. (d_handle_option): Handle OPT_fcheckaction_, OPT_fdump_c___spec_, OPT_fdump_c___spec_verbose, OPT_fextern_std_, OPT_fpreview, OPT_revert, OPT_fsave_mixins_, and OPT_ftransition. (d_post_options): Propagate dip1021 and dip1000 preview flags to dip25, and flag_diagnostics_show_caret to printErrorContext. (d_add_entrypoint_module): Remove. (d_parse_file): Update for new front-end interface. (d_type_promotes_to): Likewise. (d_types_compatible_p): Likewise. * d-longdouble.cc (CTFloat::zero): Remove. (CTFloat::one): Remove. (CTFloat::minusone): Remove. (CTFloat::half): Remove. * d-system.h (POSIX): Remove. (realpath): Remove. (isalpha): Remove. (isalnum): Remove. (isdigit): Remove. (islower): Remove. (isprint): Remove. (isspace): Remove. (isupper): Remove. (isxdigit): Remove. (tolower): Remove. (_mkdir): Remove. (INT32_MAX): Remove. (INT32_MIN): Remove. (INT64_MIN): Remove. (UINT32_MAX): Remove. (UINT64_MAX): Remove. * d-target.cc: Include calls.h. (target): Remove. (define_float_constants): Remove initialization of snan. (Target::_init): Update for new front-end interface. (Target::isVectorTypeSupported): Likewise. (Target::isVectorOpSupported): Remove cases for unordered operators. (TargetCPP::typeMangle): Update for new front-end interface. (TargetCPP::parameterType): Likewise. (Target::systemLinkage): Likewise. (Target::isReturnOnStack): Likewise. (Target::isCalleeDestroyingArgs): Define. (Target::preferPassByRef): Define. * d-tree.h (d_add_entrypoint_module): Remove. * decl.cc (gcc_attribute_p): Update for new front-end interface. (apply_pragma_crt): Define. (DeclVisitor::visit(PragmaDeclaration *)): Handle pragmas crt_constructor and crt_destructor. (DeclVisitor::visit(TemplateDeclaration *)): Update for new front-end interface. (DeclVisitor::visit): Likewise. (DeclVisitor::finish_vtable): Likewise. (get_symbol_decl): Error if template has more than one nesting context. Update for new front-end interface. (make_thunk): Update for new front-end interface. (get_vtable_decl): Likewise. * expr.cc (ExprVisitor::visit): Likewise. (build_return_dtor): Likewise. * imports.cc (ImportVisitor::visit): Likewise. * intrinsics.cc: Include dmd/expression.h. Remove include of dmd/mangle.h. (maybe_set_intrinsic): Update for new front-end interface. * intrinsics.def (INTRINSIC_ROL): Update intrinsic signature. (INTRINSIC_ROR): Likewise. (INTRINSIC_ROR_TIARG): Likewise. (INTRINSIC_TOPREC): Likewise. (INTRINSIC_TOPRECL): Likewise. (INTRINSIC_TAN): Update intrinsic module and signature. (INTRINSIC_ISNAN): Likewise. (INTRINSIC_ISFINITE): Likewise. (INTRINSIC_COPYSIGN): Define intrinsic. (INTRINSIC_COPYSIGNI): Define intrinsic. (INTRINSIC_EXP): Update intrinsic module. (INTRINSIC_EXPM1): Likewise. (INTRINSIC_EXP2): Likewise. (INTRINSIC_LOG): Likewise. (INTRINSIC_LOG2): Likewise. (INTRINSIC_LOG10): Likewise. (INTRINSIC_POW): Likewise. (INTRINSIC_ROUND): Likewise. (INTRINSIC_FLOORF): Likewise. (INTRINSIC_FLOOR): Likewise. (INTRINSIC_FLOORL): Likewise. (INTRINSIC_CEILF): Likewise. (INTRINSIC_CEIL): Likewise. (INTRINSIC_CEILL): Likewise. (INTRINSIC_TRUNC): Likewise. (INTRINSIC_FMIN): Likewise. (INTRINSIC_FMAX): Likewise. (INTRINSIC_FMA): Likewise. (INTRINSIC_VA_ARG): Update intrinsic signature. (INTRINSIC_VASTART): Likewise. * lang.opt (fcheck=): Add alternate aliases for contract switches. (fcheckaction=): New option. (check_action): New Enum and EnumValue entries. (fdump-c++-spec-verbose): New option. (fdump-c++-spec=): New option. (fextern-std=): New option. (extern_stdcpp): New Enum and EnumValue entries (fpreview=): New options. (frevert=): New options. (fsave-mixins): New option. (ftransition=): Update options. * modules.cc (get_internal_fn): Replace Prot with Visibility. (build_internal_fn): Likewise. (build_dso_cdtor_fn): Likewise. (build_module_tree): Remove check for __entrypoint module. * runtime.def (P5): Define. (ARRAYBOUNDS_SLICEP): Define. (ARRAYBOUNDS_INDEXP): Define. (NEWTHROW): Define. (ADCMP2): Remove. (ARRAYCAST): Remove. (SWITCH_STRING): Remove. (SWITCH_USTRING): Remove. (SWITCH_DSTRING): Remove. (SWITCH_ERROR): Remove. * toir.cc (IRVisitor::visit): Update for new front-end interface. (IRVisitor::check_previous_goto): Remove checks for case and default statements. (IRVisitor::visit(SwitchStatement *)): Remove handling of string switch conditions. * typeinfo.cc: Include d-frontend.h. (get_typeinfo_kind): Update for new front-end interface. (make_frontend_typeinfo): Likewise. (TypeInfoVisitor::visit): Likewise. (builtin_typeinfo_p): Likewise. (get_typeinfo_decl): Likewise. (build_typeinfo): Likewise. * types.cc (valist_array_p): Likewise. (make_array_type): Likewise. (merge_aggregate_types): Likewise. (TypeVisitor::visit(TypeBasic *)): Likewise. (TypeVisitor::visit(TypeFunction *)): Likewise. (TypeVisitor::visit(TypeStruct *)): Update comment. * verstr.h: Removed. * d-frontend.h: New file. gcc/po/ChangeLog: * EXCLUDES: Remove d/dmd sources from list. gcc/testsuite/ChangeLog: * gdc.dg/Wcastresult2.d: Update test. * gdc.dg/asm1.d: Likewise. * gdc.dg/asm2.d: Likewise. * gdc.dg/asm3.d: Likewise. * gdc.dg/gdc282.d: Likewise. * gdc.dg/imports/gdc170.d: Likewise. * gdc.dg/intrinsics.d: Likewise. * gdc.dg/pr101672.d: Likewise. * gdc.dg/pr90650a.d: Likewise. * gdc.dg/pr90650b.d: Likewise. * gdc.dg/pr94777a.d: Likewise. * gdc.dg/pr95250.d: Likewise. * gdc.dg/pr96869.d: Likewise. * gdc.dg/pr98277.d: Likewise. * gdc.dg/pr98457.d: Likewise. * gdc.dg/simd1.d: Likewise. * gdc.dg/simd2a.d: Likewise. * gdc.dg/simd2b.d: Likewise. * gdc.dg/simd2c.d: Likewise. * gdc.dg/simd2d.d: Likewise. * gdc.dg/simd2e.d: Likewise. * gdc.dg/simd2f.d: Likewise. * gdc.dg/simd2g.d: Likewise. * gdc.dg/simd2h.d: Likewise. * gdc.dg/simd2i.d: Likewise. * gdc.dg/simd2j.d: Likewise. * gdc.dg/simd7951.d: Likewise. * gdc.dg/torture/gdc309.d: Likewise. * gdc.dg/torture/pr94424.d: Likewise. * gdc.dg/torture/pr94777b.d: Likewise. * lib/gdc-utils.exp (gdc-convert-args): Handle new compiler options. (gdc-convert-test): Handle CXXFLAGS, EXTRA_OBJC_SOURCES, and ARG_SETS test directives. (gdc-do-test): Only import modules in the test run directory. * gdc.dg/pr94777c.d: New test. * gdc.dg/pr96156b.d: New test. * gdc.dg/pr96157c.d: New test. * gdc.dg/simd_ctfe.d: New test. * gdc.dg/torture/simd17344.d: New test. * gdc.dg/torture/simd20052.d: New test. * gdc.dg/torture/simd6.d: New test. * gdc.dg/torture/simd7.d: New test. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e6caaab9. * libdruntime/Makefile.am (D_EXTRA_FLAGS): Build libdruntime with -fpreview=dip1000, -fpreview=fieldwise, and -fpreview=dtorfields. (ALL_DRUNTIME_SOURCES): Add DRUNTIME_DSOURCES_STDCXX. (DRUNTIME_DSOURCES): Update list of C binding modules. (DRUNTIME_DSOURCES_STDCXX): Likewise. (DRUNTIME_DSOURCES_LINUX): Likewise. (DRUNTIME_DSOURCES_OPENBSD): Likewise. (DRUNTIME_DISOURCES): Remove __entrypoint.di. * libdruntime/Makefile.in: Regenerated. * libdruntime/__entrypoint.di: Removed. * libdruntime/gcc/deh.d (_d_isbaseof): Update signature. (_d_createTrace): Likewise. (__gdc_begin_catch): Remove reference to the exception. (_d_throw): Increment reference count of thrown object before unwind. (__gdc_personality): Chain exceptions with Throwable.chainTogether. * libdruntime/gcc/emutls.d: Update imports. * libdruntime/gcc/sections/elf.d: Update imports. (DSO.moduleGroup): Update signature. * libdruntime/gcc/sections/macho.d: Update imports. (DSO.moduleGroup): Update signature. * libdruntime/gcc/sections/pecoff.d: Update imports. (DSO.moduleGroup): Update signature. * src/MERGE: Merge upstream phobos 5ab9ad256. * src/Makefile.am (D_EXTRA_DFLAGS): Add -fpreview=dip1000 and -fpreview=dtorfields flags. (PHOBOS_DSOURCES): Update list of std modules. * src/Makefile.in: Regenerate. * testsuite/lib/libphobos.exp (libphobos-dg-test): Handle assembly compile types. (dg-test): Override. (additional_prunes): Define. (libphobos-dg-prune): Filter any additional_prunes set by tests. * testsuite/libphobos.aa/test_aa.d: Update test. * testsuite/libphobos.druntime/druntime.exp (version_flags): Add -fversion=CoreUnittest. * testsuite/libphobos.druntime_shared/druntime_shared.exp (version_flags): Add -fversion=CoreUnittest -fversion=Shared. * testsuite/libphobos.exceptions/unknown_gc.d: Update test. * testsuite/libphobos.hash/test_hash.d: Update test. * testsuite/libphobos.phobos/phobos.exp (version_flags): Add -fversion=StdUnittest * testsuite/libphobos.phobos_shared/phobos_shared.exp (version_flags): Likewise. * testsuite/libphobos.shared/host.c: Update test. * testsuite/libphobos.shared/load.d: Update test. * testsuite/libphobos.shared/load_13414.d: Update test. * testsuite/libphobos.thread/fiber_guard_page.d: Update test. * testsuite/libphobos.thread/tlsgc_sections.d: Update test. * testsuite/testsuite_flags.in: Add -fpreview=dip1000 to --gdcflags. * testsuite/libphobos.shared/link_mod_collision.d: Removed. * testsuite/libphobos.shared/load_mod_collision.d: Removed. * testsuite/libphobos.betterc/betterc.exp: New test. * testsuite/libphobos.config/config.exp: New test. * testsuite/libphobos.gc/gc.exp: New test. * testsuite/libphobos.imports/imports.exp: New test. * testsuite/libphobos.lifetime/lifetime.exp: New test. * testsuite/libphobos.unittest/unittest.exp: New test.
Diffstat (limited to 'libphobos/src/std/internal')
-rw-r--r--libphobos/src/std/internal/attributes.d11
-rw-r--r--libphobos/src/std/internal/cstring.d318
-rw-r--r--libphobos/src/std/internal/math/biguintcore.d822
-rw-r--r--libphobos/src/std/internal/math/biguintnoasm.d18
-rw-r--r--libphobos/src/std/internal/math/errorfunction.d139
-rw-r--r--libphobos/src/std/internal/math/gammafunction.d303
-rw-r--r--libphobos/src/std/internal/memory.d58
-rw-r--r--libphobos/src/std/internal/scopebuffer.d29
-rw-r--r--libphobos/src/std/internal/test/dummyrange.d11
-rw-r--r--libphobos/src/std/internal/windows/advapi32.d4
10 files changed, 1104 insertions, 609 deletions
diff --git a/libphobos/src/std/internal/attributes.d b/libphobos/src/std/internal/attributes.d
new file mode 100644
index 0000000..2405326
--- /dev/null
+++ b/libphobos/src/std/internal/attributes.d
@@ -0,0 +1,11 @@
+module std.internal.attributes;
+
+/**
+Used to annotate `unittest`s which need to be tested in a `-betterC` environment.
+
+Such `unittest`s will be compiled and executed without linking druntime in, with
+a `__traits(getUnitTests, mixin(__MODULE__))` style test runner.
+Note that just like any other `unittest` in phobos, they will also be compiled
+and executed without `-betterC`.
+*/
+package(std) enum betterC = 1;
diff --git a/libphobos/src/std/internal/cstring.d b/libphobos/src/std/internal/cstring.d
index e5bc7f7..a61ee81 100644
--- a/libphobos/src/std/internal/cstring.d
+++ b/libphobos/src/std/internal/cstring.d
@@ -11,7 +11,7 @@ License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: Denis Shelomovskij
Macros:
-COREREF = $(HTTP dlang.org/phobos/core_$1.html#$2, $(D core.$1.$2))
+COREREF = $(HTTP dlang.org/phobos/core_$1.html#$2, `core.$1.$2`)
*/
module std.internal.cstring;
@@ -24,16 +24,16 @@ module std.internal.cstring;
import core.sys.posix.stdlib : setenv;
import std.exception : enforce;
- void setEnvironment(in char[] name, in char[] value)
+ void setEnvironment(scope const(char)[] name, scope const(char)[] value)
{ enforce(setenv(name.tempCString(), value.tempCString(), 1) != -1); }
}
version (Windows)
{
- import core.sys.windows.windows : SetEnvironmentVariableW;
+ import core.sys.windows.winbase : SetEnvironmentVariableW;
import std.exception : enforce;
- void setEnvironment(in char[] name, in char[] value)
+ void setEnvironment(scope const(char)[] name, scope const(char)[] value)
{ enforce(SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW())); }
}
}
@@ -41,18 +41,6 @@ module std.internal.cstring;
import std.range;
import std.traits;
-version (unittest)
-@property inout(C)[] asArray(C)(inout C* cstr) pure nothrow @nogc @trusted
-if (isSomeChar!C)
-in { assert(cstr); }
-body
-{
- size_t length = 0;
- while (cstr[length])
- ++length;
- return cstr[0 .. length];
-}
-
/**
Creates temporary 0-terminated $(I C string) with copy of passed text.
@@ -63,8 +51,8 @@ Params:
Returns:
The value returned is implicitly convertible to $(D const To*) and
-has two properties: $(D ptr) to access $(I C string) as $(D const To*)
-and $(D buffPtr) to access it as $(D To*).
+has two properties: `ptr` to access $(I C string) as $(D const To*)
+and `buffPtr` to access it as `To*`.
The value returned can be indexed by [] to access it as an array.
@@ -77,149 +65,99 @@ primary expression.
Implementation_note:
For small strings tempCString will use stack allocated buffer,
for large strings (approximately 250 characters and more) it will
-allocate temporary one using C's $(D malloc).
+allocate temporary one using C's `malloc`.
Note:
This function is intended to be used in function call expression (like
-$(D strlen(str.tempCString()))). Incorrect usage of this function may
+`strlen(str.tempCString())`). Incorrect usage of this function may
lead to memory corruption.
See $(RED WARNING) in $(B Examples) section.
*/
-auto tempCString(To = char, From)(From str)
+auto tempCString(To = char, From)(scope From str)
if (isSomeChar!To && (isInputRange!From || isSomeString!From) &&
isSomeChar!(ElementEncodingType!From))
{
-
alias CF = Unqual!(ElementEncodingType!From);
- enum To* useStack = () @trusted { return cast(To*) size_t.max; }();
-
- static struct Res
- {
- @trusted:
- nothrow @nogc:
+ auto res = TempCStringBuffer!To.trustedVoidInit(); // expensive to fill _buff[]
- @disable this();
- @disable this(this);
- alias ptr this;
-
- @property inout(To)* buffPtr() inout pure
- {
- return _ptr == useStack ? _buff.ptr : _ptr;
- }
+ // Note: res._ptr can't point to res._buff as structs are movable.
- @property const(To)* ptr() const pure
+ // https://issues.dlang.org/show_bug.cgi?id=14980
+ static if (isSomeString!From)
+ {
+ if (str is null)
{
- return buffPtr;
+ res._length = 0;
+ res._ptr = null;
+ return res;
}
+ }
- const(To)[] opIndex() const pure
+ // Use slice assignment if available.
+ static if (To.sizeof == CF.sizeof && is(typeof(res._buff[0 .. str.length] = str[])))
+ {
+ if (str.length < res._buff.length)
{
- return buffPtr[0 .. _length];
+ res._buff[0 .. str.length] = str[];
+ res._buff[str.length] = 0;
+ res._ptr = res.useStack;
}
-
- ~this()
+ else
{
- if (_ptr != useStack)
+ import std.internal.memory : enforceMalloc;
+ if (false)
{
- import core.stdc.stdlib : free;
- free(_ptr);
+ // This code is removed by the compiler but causes `@safe`ty
+ // to be inferred correctly.
+ CF[0] x;
+ x[] = str[0 .. 0];
}
+ res._ptr = () @trusted {
+ auto p = cast(CF*) enforceMalloc((str.length + 1) * CF.sizeof);
+ p[0 .. str.length] = str[];
+ p[str.length] = 0;
+ return cast(To*) p;
+ }();
}
-
- private:
- To* _ptr;
- size_t _length; // length of the string
-
- // the 'small string optimization'
- version (unittest)
- {
- // smaller size to trigger reallocations. Padding is to account for
- // unittest/non-unittest cross-compilation (to avoid corruption)
- To[16 / To.sizeof] _buff;
- To[(256 - 16) / To.sizeof] _unittest_pad;
- }
- else
- {
- To[256 / To.sizeof] _buff; // production size
- }
-
- static Res trustedVoidInit() { Res res = void; return res; }
+ res._length = str.length;
+ return res;
}
-
- Res res = Res.trustedVoidInit(); // expensive to fill _buff[]
-
- // Note: res._ptr can't point to res._buff as structs are movable.
-
- To[] p;
- bool p_is_onstack = true;
- size_t i;
-
- static To[] trustedRealloc(To[] buf, size_t i, To[] res, size_t strLength, bool res_is_onstack)
- @trusted @nogc nothrow
+ else
{
- pragma(inline, false); // because it's rarely called
-
- import core.exception : onOutOfMemoryError;
- import core.stdc.stdlib : malloc, realloc;
- import core.stdc.string : memcpy;
+ static assert(!(isSomeString!From && CF.sizeof == To.sizeof), "Should be using slice assignment.");
+ To[] p = res._buff;
+ size_t i;
- if (res_is_onstack)
+ size_t strLength;
+ static if (hasLength!From)
{
- size_t newlen = res.length * 3 / 2;
- if (newlen <= strLength)
- newlen = strLength + 1; // +1 for terminating 0
- auto ptr = cast(To*) malloc(newlen * To.sizeof);
- if (!ptr)
- onOutOfMemoryError();
- memcpy(ptr, res.ptr, i * To.sizeof);
- return ptr[0 .. newlen];
+ strLength = str.length;
}
+ import std.utf : byUTF;
+ static if (isSomeString!From)
+ auto r = cast(const(CF)[])str; // because inout(CF) causes problems with byUTF
else
+ alias r = str;
+ To[] heapBuffer;
+ foreach (const c; byUTF!(Unqual!To)(r))
{
- if (buf.length >= size_t.max / (2 * To.sizeof))
- onOutOfMemoryError();
- const newlen = buf.length * 3 / 2;
- auto ptr = cast(To*) realloc(buf.ptr, newlen * To.sizeof);
- if (!ptr)
- onOutOfMemoryError();
- return ptr[0 .. newlen];
- }
- }
-
- size_t strLength;
- static if (hasLength!From)
- {
- strLength = str.length;
- }
- import std.utf : byUTF;
- static if (isSomeString!From)
- {
- auto r = cast(const(CF)[])str; // because inout(CF) causes problems with byUTF
- if (r is null) // Bugzilla 14980
- {
- res._ptr = null;
- return res;
- }
- }
- else
- alias r = str;
- To[] q = res._buff;
- foreach (const c; byUTF!(Unqual!To)(r))
- {
- if (i + 1 == q.length)
- {
- p = trustedRealloc(p, i, res._buff, strLength, p_is_onstack);
- p_is_onstack = false;
- q = p;
+ if (i + 1 == p.length)
+ {
+ if (heapBuffer is null)
+ heapBuffer = trustedReallocStack(p, strLength);
+ else
+ heapBuffer = trustedRealloc(heapBuffer);
+ p = heapBuffer;
+ }
+ p[i++] = c;
}
- q[i++] = c;
+ p[i] = 0;
+ res._length = i;
+ res._ptr = (heapBuffer is null ? res.useStack : &heapBuffer[0]);
+ return res;
}
- q[i] = 0;
- res._length = i;
- res._ptr = p_is_onstack ? useStack : &p[0];
- return res;
}
///
@@ -244,21 +182,30 @@ nothrow @nogc @system unittest
// both primary expressions are ended.
}
-@safe nothrow @nogc unittest
+@safe pure nothrow @nogc unittest
{
- assert("abc".tempCString().asArray == "abc");
- assert("abc"d.tempCString().ptr.asArray == "abc");
- assert("abc".tempCString!wchar().buffPtr.asArray == "abc"w);
+ static inout(C)[] arrayFor(C)(inout(C)* cstr) pure nothrow @nogc @trusted
+ {
+ assert(cstr);
+ size_t length = 0;
+ while (cstr[length])
+ ++length;
+ return cstr[0 .. length];
+ }
+
+ assert(arrayFor("abc".tempCString()) == "abc");
+ assert(arrayFor("abc"d.tempCString().ptr) == "abc");
+ assert(arrayFor("abc".tempCString!wchar().buffPtr) == "abc"w);
import std.utf : byChar, byWchar;
char[300] abc = 'a';
- assert(tempCString(abc[].byChar).buffPtr.asArray == abc);
- assert(tempCString(abc[].byWchar).buffPtr.asArray == abc);
+ assert(arrayFor(tempCString(abc[].byChar).buffPtr) == abc);
+ assert(arrayFor(tempCString(abc[].byWchar).buffPtr) == abc);
assert(tempCString(abc[].byChar)[] == abc);
}
-// Bugzilla 14980
-nothrow @nogc @safe unittest
+// https://issues.dlang.org/show_bug.cgi?id=14980
+pure nothrow @nogc @safe unittest
{
const(char[]) str = null;
auto res = tempCString(str);
@@ -267,4 +214,99 @@ nothrow @nogc @safe unittest
}
version (Windows)
- alias tempCStringW = tempCString!(wchar, const(char)[]);
+{
+ import core.sys.windows.winnt : WCHAR;
+ alias tempCStringW = tempCString!(WCHAR, const(char)[]);
+}
+
+private struct TempCStringBuffer(To = char)
+{
+@trusted pure nothrow @nogc:
+
+ @disable this();
+ @disable this(this);
+ alias ptr this; /// implicitly covert to raw pointer
+
+ @property inout(To)* buffPtr() inout
+ {
+ return _ptr == useStack ? _buff.ptr : _ptr;
+ }
+
+ @property const(To)* ptr() const
+ {
+ return buffPtr;
+ }
+
+ const(To)[] opIndex() const pure
+ {
+ return buffPtr[0 .. _length];
+ }
+
+ ~this()
+ {
+ if (_ptr != useStack)
+ {
+ import core.memory : pureFree;
+ pureFree(_ptr);
+ }
+ }
+
+private:
+ enum To* useStack = () @trusted { return cast(To*) size_t.max; }();
+
+ To* _ptr;
+ size_t _length; // length of the string
+ version (StdUnittest)
+ // the 'small string optimization'
+ {
+ // smaller size to trigger reallocations. Padding is to account for
+ // unittest/non-unittest cross-compilation (to avoid corruption)
+ To[16 / To.sizeof] _buff;
+ To[(256 - 16) / To.sizeof] _unittest_pad;
+ }
+ else
+ {
+ To[256 / To.sizeof] _buff; // production size
+ }
+
+ static TempCStringBuffer trustedVoidInit() { TempCStringBuffer res = void; return res; }
+}
+
+private To[] trustedRealloc(To)(return scope To[] buf)
+ @trusted @nogc pure nothrow
+{
+ pragma(inline, false); // because it's rarely called
+ import std.internal.memory : enforceRealloc;
+
+ const size_t newlen = buf.length * 3 / 2;
+ if (buf.length >= size_t.max / (2 * To.sizeof))
+ {
+ version (D_Exceptions)
+ {
+ import core.exception : onOutOfMemoryError;
+ onOutOfMemoryError();
+ }
+ else
+ {
+ assert(0, "Memory allocation failed");
+ }
+ }
+ auto ptr = cast(To*) enforceRealloc(buf.ptr, newlen * To.sizeof);
+ return ptr[0 .. newlen];
+
+}
+
+private To[] trustedReallocStack(To)(scope To[] buf, size_t strLength)
+ @trusted @nogc pure nothrow
+{
+ pragma(inline, false); // because it's rarely called
+
+ import std.internal.memory : enforceMalloc;
+
+ size_t newlen = buf.length * 3 / 2;
+ if (newlen <= strLength)
+ newlen = strLength + 1; // +1 for terminating 0
+ auto ptr = cast(To*) enforceMalloc(newlen * To.sizeof);
+ ptr[0 .. buf.length] = buf[];
+ return ptr[0 .. newlen];
+}
diff --git a/libphobos/src/std/internal/math/biguintcore.d b/libphobos/src/std/internal/math/biguintcore.d
index 6fc2d16..59d7842 100644
--- a/libphobos/src/std/internal/math/biguintcore.d
+++ b/libphobos/src/std/internal/math/biguintcore.d
@@ -35,43 +35,184 @@ module std.internal.math.biguintcore;
version (D_InlineAsm_X86)
{
- import std.internal.math.biguintx86;
-}
-else
-{
- import std.internal.math.biguintnoasm;
+ static import std.internal.math.biguintx86;
}
+static import std.internal.math.biguintnoasm;
+
+import std.internal.math.biguintnoasm : BigDigit, KARATSUBALIMIT,
+ KARATSUBASQUARELIMIT;
alias multibyteAdd = multibyteAddSub!('+');
alias multibyteSub = multibyteAddSub!('-');
-
-import core.cpuid;
+private import std.traits;
+private import std.range.primitives;
public import std.ascii : LetterCase;
import std.range.primitives;
import std.traits;
-shared static this()
+private:
+
+// dipatchers to the right low-level primitives. Added to allow BigInt CTFE for
+// 32 bit systems (https://issues.dlang.org/show_bug.cgi?id=14767) although it's
+// used by the other architectures too.
+// See comments below in case it has to be refactored.
+version (X86)
+uint multibyteAddSub(char op)(uint[] dest, const(uint)[] src1, const (uint)[] src2, uint carry)
{
- CACHELIMIT = core.cpuid.datacache[0].size*1024/2;
+ // must be checked before, otherwise D_InlineAsm_X86 is true.
+ if (__ctfe)
+ return std.internal.math.biguintnoasm.multibyteAddSub!op(dest, src1, src2, carry);
+ // Runtime.
+ else version (D_InlineAsm_X86)
+ return std.internal.math.biguintx86.multibyteAddSub!op(dest, src1, src2, carry);
+ // Runtime if no asm available.
+ else
+ return std.internal.math.biguintnoasm.multibyteAddSub!op(dest, src1, src2, carry);
}
+// Any other architecture
+else alias multibyteAddSub = std.internal.math.biguintnoasm.multibyteAddSub;
+
+version (X86)
+uint multibyteIncrementAssign(char op)(uint[] dest, uint carry)
+{
+ if (__ctfe)
+ return std.internal.math.biguintnoasm.multibyteIncrementAssign!op(dest, carry);
+ else version (D_InlineAsm_X86)
+ return std.internal.math.biguintx86.multibyteIncrementAssign!op(dest, carry);
+ else
+ return std.internal.math.biguintnoasm.multibyteIncrementAssign!op(dest, carry);
+}
+else alias multibyteIncrementAssign = std.internal.math.biguintnoasm.multibyteIncrementAssign;
+
+version (X86)
+uint multibyteShl()(uint[] dest, const(uint)[] src, uint numbits)
+{
+ if (__ctfe)
+ return std.internal.math.biguintnoasm.multibyteShl(dest, src, numbits);
+ else version (D_InlineAsm_X86)
+ return std.internal.math.biguintx86.multibyteShl(dest, src, numbits);
+ else
+ return std.internal.math.biguintnoasm.multibyteShl(dest, src, numbits);
+}
+else alias multibyteShl = std.internal.math.biguintnoasm.multibyteShl;
+
+version (X86)
+void multibyteShr()(uint[] dest, const(uint)[] src, uint numbits)
+{
+ if (__ctfe)
+ std.internal.math.biguintnoasm.multibyteShr(dest, src, numbits);
+ else version (D_InlineAsm_X86)
+ std.internal.math.biguintx86.multibyteShr(dest, src, numbits);
+ else
+ std.internal.math.biguintnoasm.multibyteShr(dest, src, numbits);
+}
+else alias multibyteShr = std.internal.math.biguintnoasm.multibyteShr;
+
+version (X86)
+uint multibyteMul()(uint[] dest, const(uint)[] src, uint multiplier, uint carry)
+{
+ if (__ctfe)
+ return std.internal.math.biguintnoasm.multibyteMul(dest, src, multiplier, carry);
+ else version (D_InlineAsm_X86)
+ return std.internal.math.biguintx86.multibyteMul(dest, src, multiplier, carry);
+ else
+ return std.internal.math.biguintnoasm.multibyteMul(dest, src, multiplier, carry);
+}
+else alias multibyteMul = std.internal.math.biguintnoasm.multibyteMul;
+
+version (X86)
+uint multibyteMulAdd(char op)(uint[] dest, const(uint)[] src, uint multiplier, uint carry)
+{
+ if (__ctfe)
+ return std.internal.math.biguintnoasm.multibyteMulAdd!op(dest, src, multiplier, carry);
+ else version (D_InlineAsm_X86)
+ return std.internal.math.biguintx86.multibyteMulAdd!op(dest, src, multiplier, carry);
+ else
+ return std.internal.math.biguintnoasm.multibyteMulAdd!op(dest, src, multiplier, carry);
+}
+else alias multibyteMulAdd = std.internal.math.biguintnoasm.multibyteMulAdd;
+
+version (X86)
+void multibyteMultiplyAccumulate()(uint[] dest, const(uint)[] left, const(uint)[] right)
+{
+ if (__ctfe)
+ std.internal.math.biguintnoasm.multibyteMultiplyAccumulate(dest, left, right);
+ else version (D_InlineAsm_X86)
+ std.internal.math.biguintx86.multibyteMultiplyAccumulate(dest, left, right);
+ else
+ std.internal.math.biguintnoasm.multibyteMultiplyAccumulate(dest, left, right);
+}
+else alias multibyteMultiplyAccumulate = std.internal.math.biguintnoasm.multibyteMultiplyAccumulate;
+
+version (X86)
+uint multibyteDivAssign()(uint[] dest, uint divisor, uint overflow)
+{
+ if (__ctfe)
+ return std.internal.math.biguintnoasm.multibyteDivAssign(dest, divisor, overflow);
+ else version (D_InlineAsm_X86)
+ return std.internal.math.biguintx86.multibyteDivAssign(dest, divisor, overflow);
+ else
+ return std.internal.math.biguintnoasm.multibyteDivAssign(dest, divisor, overflow);
+}
+else alias multibyteDivAssign = std.internal.math.biguintnoasm.multibyteDivAssign;
+
+version (X86)
+void multibyteAddDiagonalSquares()(uint[] dest, const(uint)[] src)
+{
+ if (__ctfe)
+ std.internal.math.biguintnoasm.multibyteAddDiagonalSquares(dest, src);
+ else version (D_InlineAsm_X86)
+ std.internal.math.biguintx86.multibyteAddDiagonalSquares(dest, src);
+ else
+ std.internal.math.biguintnoasm.multibyteAddDiagonalSquares(dest, src);
+}
+else alias multibyteAddDiagonalSquares = std.internal.math.biguintnoasm.multibyteAddDiagonalSquares;
+
+version (X86)
+void multibyteTriangleAccumulate()(uint[] dest, const(uint)[] x)
+{
+ if (__ctfe)
+ std.internal.math.biguintnoasm.multibyteTriangleAccumulate(dest, x);
+ else version (D_InlineAsm_X86)
+ std.internal.math.biguintx86.multibyteTriangleAccumulate(dest, x);
+ else
+ std.internal.math.biguintnoasm.multibyteTriangleAccumulate(dest, x);
+}
+else alias multibyteTriangleAccumulate = std.internal.math.biguintnoasm.multibyteTriangleAccumulate;
+
+version (X86)
+void multibyteSquare()(BigDigit[] result, const(BigDigit)[] x)
+{
+ if (__ctfe)
+ std.internal.math.biguintnoasm.multibyteSquare(result, x);
+ else version (D_InlineAsm_X86)
+ std.internal.math.biguintx86.multibyteSquare(result, x);
+ else
+ std.internal.math.biguintnoasm.multibyteSquare(result, x);
+}
+else alias multibyteSquare = std.internal.math.biguintnoasm.multibyteSquare;
-private:
// Limits for when to switch between algorithms.
-immutable size_t CACHELIMIT; // Half the size of the data cache.
+// Half the size of the data cache.
+@nogc nothrow pure @safe size_t getCacheLimit()
+{
+ import core.cpuid : dataCaches;
+ return dataCaches[0].size * 1024 / 2;
+}
enum size_t FASTDIVLIMIT = 100; // crossover to recursive division
// These constants are used by shift operations
static if (BigDigit.sizeof == int.sizeof)
{
- enum { LG2BIGDIGITBITS = 5, BIGDIGITSHIFTMASK = 31 };
+ enum { LG2BIGDIGITBITS = 5, BIGDIGITSHIFTMASK = 31 }
alias BIGHALFDIGIT = ushort;
}
else static if (BigDigit.sizeof == long.sizeof)
{
alias BIGHALFDIGIT = uint;
- enum { LG2BIGDIGITBITS = 6, BIGDIGITSHIFTMASK = 63 };
+ enum { LG2BIGDIGITBITS = 6, BIGDIGITSHIFTMASK = 63 }
}
else static assert(0, "Unsupported BigDigit size");
@@ -98,17 +239,18 @@ struct BigUint
private:
pure invariant()
{
- assert( data.length >= 1 && (data.length == 1 || data[$-1] != 0 ));
+ assert( data.length >= 1 && (data.length == 1 || data[$-1] != 0 ),
+ "Invariant requires data to not empty or zero");
}
immutable(BigDigit) [] data = ZERO;
- this(immutable(BigDigit) [] x) pure nothrow @nogc @safe
+ this(return scope immutable(BigDigit) [] x) pure nothrow @nogc @safe
{
data = x;
}
package(std) // used from: std.bigint
- this(T)(T x) pure nothrow @safe if (isIntegral!T)
+ this(T)(T x) pure nothrow @safe scope if (isIntegral!T)
{
opAssign(x);
}
@@ -118,7 +260,7 @@ private:
};
public:
// Length in uints
- @property size_t uintLength() pure nothrow const @safe @nogc
+ @property size_t uintLength() pure nothrow const @safe @nogc scope
{
static if (BigDigit.sizeof == uint.sizeof)
{
@@ -130,7 +272,7 @@ public:
((data[$-1] & 0xFFFF_FFFF_0000_0000L) ? 1 : 0);
}
}
- @property size_t ulongLength() pure nothrow const @safe @nogc
+ @property size_t ulongLength() pure nothrow const @safe @nogc scope
{
static if (BigDigit.sizeof == uint.sizeof)
{
@@ -143,7 +285,7 @@ public:
}
// The value at (cast(ulong[]) data)[n]
- ulong peekUlong(int n) pure nothrow const @safe @nogc
+ ulong peekUlong(size_t n) pure nothrow const @safe @nogc scope
{
static if (BigDigit.sizeof == int.sizeof)
{
@@ -155,7 +297,8 @@ public:
return data[n];
}
}
- uint peekUint(int n) pure nothrow const @safe @nogc
+
+ uint peekUint(size_t n) pure nothrow const @safe @nogc scope
{
static if (BigDigit.sizeof == int.sizeof)
{
@@ -167,9 +310,9 @@ public:
return (n & 1) ? cast(uint)(x >> 32) : cast(uint) x;
}
}
-public:
+
///
- void opAssign(Tulong)(Tulong u) pure nothrow @safe if (is (Tulong == ulong))
+ void opAssign(Tulong)(Tulong u) pure nothrow @safe scope if (is (Tulong == ulong))
{
if (u == 0) data = ZERO;
else if (u == 1) data = ONE;
@@ -196,13 +339,13 @@ public:
}
}
}
- void opAssign(Tdummy = void)(BigUint y) pure nothrow @nogc @safe
+ void opAssign(Tdummy = void)(BigUint y) pure nothrow @nogc @safe scope
{
this.data = y.data;
}
///
- int opCmp(Tdummy = void)(const BigUint y) pure nothrow @nogc const @safe
+ int opCmp(Tdummy = void)(const BigUint y) pure nothrow @nogc const @safe scope
{
if (data.length != y.data.length)
return (data.length > y.data.length) ? 1 : -1;
@@ -213,7 +356,7 @@ public:
}
///
- int opCmp(Tulong)(Tulong y) pure nothrow @nogc const @safe if (is (Tulong == ulong))
+ int opCmp(Tulong)(Tulong y) pure nothrow @nogc const @safe scope if (is (Tulong == ulong))
{
if (data.length > maxBigDigits!Tulong)
return 1;
@@ -239,12 +382,12 @@ public:
return 0;
}
- bool opEquals(Tdummy = void)(ref const BigUint y) pure nothrow @nogc const @safe
+ bool opEquals(Tdummy = void)(ref const BigUint y) pure nothrow @nogc const @safe scope
{
return y.data[] == data[];
}
- bool opEquals(Tdummy = void)(ulong y) pure nothrow @nogc const @safe
+ bool opEquals(Tdummy = void)(ulong y) pure nothrow @nogc const @safe scope
{
if (data.length > 2)
return false;
@@ -257,18 +400,18 @@ public:
return (data[0] == ylo);
}
- bool isZero() pure const nothrow @safe @nogc
+ bool isZero() pure const nothrow @safe @nogc scope
{
return data.length == 1 && data[0] == 0;
}
- size_t numBytes() pure nothrow const @safe @nogc
+ size_t numBytes() pure nothrow const @safe @nogc scope
{
return data.length * BigDigit.sizeof;
}
// the extra bytes are added to the start of the string
- char [] toDecimalString(int frontExtraBytes) const pure nothrow
+ char [] toDecimalString(int frontExtraBytes) const pure nothrow @safe scope
{
immutable predictlength = 20+20*(data.length/2); // just over 19
char [] buff = new char[frontExtraBytes + predictlength];
@@ -285,7 +428,7 @@ public:
*/
char [] toHexString(int frontExtraBytes, char separator = 0,
int minPadding=0, char padChar = '0',
- LetterCase letterCase = LetterCase.upper) const pure nothrow @safe
+ LetterCase letterCase = LetterCase.upper) const pure nothrow @safe scope
{
// Calculate number of extra padding bytes
size_t extraPad = (minPadding > data.length * 2 * BigDigit.sizeof)
@@ -349,7 +492,7 @@ public:
/**
* Convert to an octal string.
*/
- char[] toOctalString() const
+ char[] toOctalString() pure nothrow @safe const scope
{
auto predictLength = 1 + data.length*BigDigitBits / 3;
char[] buff = new char[predictLength];
@@ -358,7 +501,7 @@ public:
}
// return false if invalid character found
- bool fromHexString(Range)(Range s) if (
+ bool fromHexString(Range)(Range s) scope if (
isBidirectionalRange!Range && isSomeChar!(ElementType!Range))
{
import std.range : walkLength;
@@ -427,7 +570,7 @@ public:
}
// return true if OK; false if erroneous characters found
- bool fromDecimalString(Range)(Range s) if (
+ bool fromDecimalString(Range)(Range s) scope if (
isForwardRange!Range && isSomeChar!(ElementType!Range))
{
import std.range : walkLength;
@@ -452,14 +595,125 @@ public:
return true;
}
+ void fromMagnitude(Range)(Range magnitude) scope
+ if (isInputRange!Range
+ && (isForwardRange!Range || hasLength!Range)
+ && isUnsigned!(ElementType!Range))
+ {
+ while (!magnitude.empty && magnitude.front == 0)
+ magnitude.popFront;
+ static if (hasLength!Range)
+ immutable inputLen = magnitude.length;
+ else
+ immutable inputLen = magnitude.save.walkLength;
+ if (!inputLen)
+ {
+ this.data = ZERO;
+ return;
+ }
+ // `magnitude` has its most significant element first but BigUint.data
+ // stores the most significant last.
+ BigDigit[] newDigits;
+ alias E = ElementType!Range;
+ static if (E.sizeof == BigDigit.sizeof)
+ {
+ newDigits = new BigDigit[inputLen];
+ foreach_reverse (ref digit; newDigits)
+ {
+ digit = magnitude.front;
+ magnitude.popFront();
+ }
+ }
+ else static if (E.sizeof < BigDigit.sizeof)
+ {
+ enum elementsPerDigit = BigDigit.sizeof / E.sizeof;
+ newDigits = new BigDigit[(inputLen + elementsPerDigit - 1) / elementsPerDigit];
+ immutable remainder = inputLen % elementsPerDigit;
+ // If there is a remainder specially assemble the most significant digit.
+ if (remainder)
+ {
+ BigDigit tmp = magnitude.front;
+ magnitude.popFront();
+ foreach (_; 1 .. remainder)
+ {
+ tmp = (tmp << (E.sizeof * 8)) | magnitude.front;
+ magnitude.popFront();
+ }
+ newDigits[$-1] = tmp;
+ }
+ // Assemble full digits from most to least significant.
+ foreach_reverse (ref digit; newDigits[0 .. $ - int(remainder != 0)])
+ {
+ BigDigit tmp;
+ static foreach (n; 0 .. elementsPerDigit)
+ {
+ tmp |= cast(BigDigit) magnitude.front <<
+ ((BigDigit.sizeof - (E.sizeof * (n + 1))) * 8);
+ magnitude.popFront();
+ }
+ digit = tmp;
+ }
+ }
+ else static if (E.sizeof > BigDigit.sizeof)
+ {
+ enum digitsPerElement = E.sizeof / BigDigit.sizeof;
+ newDigits = new BigDigit[inputLen * digitsPerElement];
+ size_t i = newDigits.length - 1;
+ foreach (element; magnitude)
+ {
+ static foreach (n; 0 .. digitsPerElement)
+ newDigits[i - n] =
+ cast(BigDigit) (element >> ((E.sizeof - (BigDigit.sizeof * (n + 1))) * 8));
+ i -= digitsPerElement;
+ }
+ while (newDigits[$-1] == 0)
+ newDigits = newDigits[0 .. $-1];
+ }
+ else
+ static assert(0);
+ this.data = trustedAssumeUnique(newDigits);
+ return;
+ }
+
+ nothrow pure @safe unittest
+ {
+ immutable BigDigit[] referenceData = [BigDigit(0x2003_4005), 0x6007_8009, 0xABCD];
+ // Internal representation is most-significant-last but `fromMagnitude`
+ // argument is most-significant-first.
+ immutable BigDigit[] referenceMagnitude = [BigDigit(0xABCD), 0x6007_8009, 0x2003_4005];
+ BigUint b;
+ // Test with reference magnitude.
+ b.fromMagnitude(referenceMagnitude);
+ assert(b.data == referenceData);
+ // Test ubyte array.
+ import std.bitmanip : nativeToBigEndian;
+ ubyte[] ubyteMagnitude = nativeToBigEndian(referenceMagnitude[0]) ~
+ nativeToBigEndian(referenceMagnitude[1]) ~
+ nativeToBigEndian(referenceMagnitude[2]);
+ b.data = ZERO;
+ b.fromMagnitude(ubyteMagnitude);
+ assert(b.data == referenceData);
+ // Test ulong array.
+ static if (BigDigit.sizeof == uint.sizeof)
+ immutable(ulong)[] ulongMagnitude = [ulong(referenceMagnitude[0]),
+ ((cast(ulong) referenceMagnitude[1]) << 32) | referenceMagnitude[2],
+ ];
+ else static if (BigDigit.sizeof == ulong.sizeof)
+ alias ulongMagnitude = referenceMagnitude;
+ b.data = ZERO;
+ b.fromMagnitude(ulongMagnitude);
+ assert(b.data == referenceData);
+ }
+
////////////////////////
//
// All of these member functions create a new BigUint.
// return x >> y
- BigUint opShr(Tulong)(Tulong y) pure nothrow const if (is (Tulong == ulong))
+ BigUint opBinary(string op, Tulong)(Tulong y) pure nothrow @safe const return scope
+ if (op == ">>" && is (Tulong == ulong))
{
- assert(y>0);
+ assert(y > 0, "Can not right shift BigUint by 0");
uint bits = cast(uint) y & BIGDIGITSHIFTMASK;
if ((y >> LG2BIGDIGITBITS) >= data.length) return BigUint(ZERO);
uint words = cast(uint)(y >> LG2BIGDIGITBITS);
@@ -480,12 +734,14 @@ public:
}
// return x << y
- BigUint opShl(Tulong)(Tulong y) pure nothrow const if (is (Tulong == ulong))
+ BigUint opBinary(string op, Tulong)(Tulong y) pure nothrow @safe const scope
+ if (op == "<<" && is (Tulong == ulong))
{
- assert(y>0);
+ assert(y > 0, "Can not left shift BigUint by 0");
if (isZero()) return this;
uint bits = cast(uint) y & BIGDIGITSHIFTMASK;
- assert((y >> LG2BIGDIGITBITS) < cast(ulong)(uint.max));
+ assert((y >> LG2BIGDIGITBITS) < cast(ulong)(uint.max),
+ "Shift result exceeds temporary store");
uint words = cast(uint)(y >> LG2BIGDIGITBITS);
BigDigit [] result = new BigDigit[data.length + words+1];
result[0 .. words] = 0;
@@ -505,15 +761,16 @@ public:
// If wantSub is false, return x + y, leaving sign unchanged
// If wantSub is true, return abs(x - y), negating sign if x < y
- static BigUint addOrSubInt(Tulong)(const BigUint x, Tulong y,
- bool wantSub, ref bool sign) pure nothrow if (is(Tulong == ulong))
+ static BigUint addOrSubInt(Tulong)(const scope BigUint x, Tulong y,
+ bool wantSub, ref bool sign) pure nothrow @safe if (is(Tulong == ulong))
{
BigUint r;
if (wantSub)
{ // perform a subtraction
if (x.data.length > 2)
{
- r.data = subInt(x.data, y);
+ // subInt returns GC allocated array, can be safely cast to immutable
+ r.data = (() @trusted => cast(immutable) subInt(x.data, y))();
}
else
{ // could change sign!
@@ -548,21 +805,23 @@ public:
}
else
{
- r.data = addInt(x.data, y);
+ // addInt returns GC allocated array, can be safely cast to immutable
+ r.data = (() @trusted => cast(immutable) addInt(x.data, y))();
}
return r;
}
// If wantSub is false, return x + y, leaving sign unchanged.
// If wantSub is true, return abs(x - y), negating sign if x<y
- static BigUint addOrSub(BigUint x, BigUint y, bool wantSub, bool *sign)
- pure nothrow
+ static BigUint addOrSub(scope BigUint x, scope BigUint y, bool wantSub, bool *sign)
+ pure nothrow @safe
{
BigUint r;
if (wantSub)
{ // perform a subtraction
bool negative;
- r.data = sub(x.data, y.data, &negative);
+ // sub returns GC allocated array, can be safely cast to immutable
+ r.data = (() @trusted => cast(immutable) sub(x.data, y.data, &negative))();
*sign ^= negative;
if (r.isZero())
{
@@ -571,19 +830,22 @@ public:
}
else
{
- r.data = add(x.data, y.data);
+ // add returns GC allocated array, can be safely cast to immutable
+ r.data = (() @trusted => cast(immutable) add(x.data, y.data))();
}
return r;
}
// return x*y.
- // y must not be zero.
- static BigUint mulInt(T = ulong)(BigUint x, T y) pure nothrow
+ static BigUint mulInt(T = ulong)(BigUint x, T y) pure nothrow @safe
{
if (y == 0 || x == 0) return BigUint(ZERO);
- uint hi = cast(uint)(y >>> 32);
- uint lo = cast(uint)(y & 0xFFFF_FFFF);
+ static if (T.sizeof * 8 <= 32)
+ uint hi = 0;
+ else
+ uint hi = cast(uint) (y >>> 32);
+ uint lo = cast(uint) (y & 0xFFFF_FFFF);
uint [] result = new BigDigit[x.data.length+1+(hi != 0)];
result[x.data.length] = multibyteMul(result[0 .. x.data.length], x.data, lo, 0);
if (hi != 0)
@@ -596,7 +858,7 @@ public:
/* return x * y.
*/
- static BigUint mul(BigUint x, BigUint y) pure nothrow
+ static BigUint mul(scope BigUint x, scope BigUint y) pure nothrow @safe
{
if (y == 0 || x == 0)
return BigUint(ZERO);
@@ -617,8 +879,8 @@ public:
}
// return x / y
- static BigUint divInt(T)(BigUint x, T y_) pure nothrow
- if ( is(Unqual!T == uint) )
+ static BigUint divInt(T)(scope return BigUint x, T y_) pure nothrow @safe
+ if ( is(immutable T == immutable uint) )
{
uint y = y_;
if (y == 1)
@@ -643,8 +905,8 @@ public:
return BigUint(removeLeadingZeros(trustedAssumeUnique(result)));
}
- static BigUint divInt(T)(BigUint x, T y) pure nothrow
- if ( is(Unqual!T == ulong) )
+ static BigUint divInt(T)(scope BigUint x, T y) pure nothrow @safe
+ if ( is(immutable T == immutable ulong) )
{
if (y <= uint.max)
return divInt!uint(x, cast(uint) y);
@@ -659,11 +921,11 @@ public:
}
// return x % y
- static uint modInt(T)(BigUint x, T y_) pure if ( is(Unqual!T == uint) )
+ static uint modInt(T)(scope BigUint x, T y_) pure if ( is(immutable T == immutable uint) )
{
import core.memory : GC;
uint y = y_;
- assert(y != 0);
+ assert(y != 0, "% 0 not allowed");
if ((y&(-y)) == y)
{ // perfect power of 2
return x.data[0] & (y-1);
@@ -680,7 +942,7 @@ public:
}
// return x / y
- static BigUint div(BigUint x, BigUint y) pure nothrow
+ static BigUint div(scope return BigUint x, scope BigUint y) pure nothrow @safe
{
if (y.data.length > x.data.length)
return BigUint(ZERO);
@@ -692,7 +954,7 @@ public:
}
// return x % y
- static BigUint mod(BigUint x, BigUint y) pure nothrow
+ static BigUint mod(scope return BigUint x, scope BigUint y) pure nothrow @safe
{
if (y.data.length > x.data.length) return x;
if (y.data.length == 1)
@@ -705,8 +967,33 @@ public:
return BigUint(removeLeadingZeros(trustedAssumeUnique(rem)));
}
+ // Return x / y in quotient, x % y in remainder
+ static void divMod(BigUint x, scope BigUint y,
+ out BigUint quotient, out BigUint remainder) pure nothrow @safe
+ {
+ /* TODO Qualify parameter `x` as `return` when it applies to `out` parameters */
+ if (y.data.length > x.data.length)
+ {
+ quotient = 0uL;
+ remainder = x;
+ }
+ else if (y.data.length == 1)
+ {
+ quotient = divInt(x, y.data[0]);
+ remainder = BigUint([modInt(x, y.data[0])]);
+ }
+ else
+ {
+ BigDigit[] quot = new BigDigit[x.data.length - y.data.length + 1];
+ BigDigit[] rem = new BigDigit[y.data.length];
+ divModInternal(quot, rem, x.data, y.data);
+ quotient = BigUint(removeLeadingZeros(trustedAssumeUnique(quot)));
+ remainder = BigUint(removeLeadingZeros(trustedAssumeUnique(rem)));
+ }
+ }
+
// return x op y
- static BigUint bitwiseOp(string op)(BigUint x, BigUint y, bool xSign, bool ySign, ref bool resultSign)
+ static BigUint bitwiseOp(string op)(scope BigUint x, scope BigUint y, bool xSign, bool ySign, ref bool resultSign)
pure nothrow @safe if (op == "|" || op == "^" || op == "&")
{
auto d1 = includeSign(x.data, y.uintLength, xSign);
@@ -733,7 +1020,7 @@ public:
* exponentiation is used.
* Memory allocation is minimized: at most one temporary BigUint is used.
*/
- static BigUint pow(BigUint x, ulong y) pure nothrow
+ static BigUint pow(scope return BigUint x, ulong y) pure nothrow @safe
{
// Deal with the degenerate cases first.
if (y == 0) return BigUint(ONE);
@@ -752,7 +1039,7 @@ public:
// If true, then x0 is that digit
// and the result will be (x0 ^^ y) * (2^^(firstnonzero*y*BigDigitBits))
BigDigit x0 = x.data[firstnonzero];
- assert(x0 != 0);
+ assert(x0 != 0, "pow(0, y) not allowed");
// Length of the non-zero portion
size_t nonzerolength = x.data.length - firstnonzero;
ulong y0;
@@ -941,9 +1228,9 @@ public:
}
// Implement toHash so that BigUint works properly as an AA key.
- size_t toHash() const @trusted nothrow
+ size_t toHash() const @nogc nothrow pure @safe scope
{
- return typeid(data).getHash(&data);
+ return .hashOf(data);
}
} // end BigUint
@@ -953,24 +1240,33 @@ public:
// ulong comparison test
BigUint a = [1];
assert(a == 1);
- assert(a < 0x8000_0000_0000_0000UL); // bug 9548
+ // https://issues.dlang.org/show_bug.cgi?id=9548
+ assert(a < 0x8000_0000_0000_0000UL);
- // bug 12234
+ // https://issues.dlang.org/show_bug.cgi?id=12234
BigUint z = [0];
assert(z == 0UL);
assert(!(z > 0UL));
assert(!(z < 0UL));
}
+// https://issues.dlang.org/show_bug.cgi?id=16223
+@system pure nothrow unittest
+{
+ BigUint a = [3];
+ int b = 5;
+ assert(BigUint.mulInt(a,b) == 15);
+}
+
// Remove leading zeros from x, to restore the BigUint invariant
-inout(BigDigit) [] removeLeadingZeros(inout(BigDigit) [] x) pure nothrow @safe
+inout(BigDigit) [] removeLeadingZeros(scope return inout(BigDigit) [] x) pure nothrow @safe
{
size_t k = x.length;
while (k>1 && x[k - 1]==0) --k;
return x[0 .. k];
}
-pure @system unittest
+pure @safe unittest
{
BigUint r = BigUint([5]);
BigUint t = BigUint([7]);
@@ -992,7 +1288,7 @@ pure @system unittest
// Pow tests
-pure @system unittest
+pure @safe unittest
{
BigUint r, s;
r.fromHexString("80000000_00000001");
@@ -1084,7 +1380,7 @@ pure nothrow @safe
}
// Encode BigInt as BigDigit array (sign and 2's complement)
-BigDigit[] includeSign(const(BigDigit) [] x, size_t minSize, bool sign)
+BigDigit[] includeSign(scope const(BigDigit) [] x, size_t minSize, bool sign)
pure nothrow @safe
{
size_t length = (x.length > minSize) ? x.length : minSize;
@@ -1139,7 +1435,7 @@ T intpow(T)(T x, ulong n) pure nothrow @safe
// returns the maximum power of x that will fit in a uint.
int highestPowerBelowUintMax(uint x) pure nothrow @safe
{
- assert(x>1);
+ assert(x > 1, "x must be greater than 1");
static immutable ubyte [22] maxpwr = [ 31, 20, 15, 13, 12, 11, 10, 10, 9, 9,
8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7];
if (x<24) return maxpwr[x-2];
@@ -1154,7 +1450,7 @@ int highestPowerBelowUintMax(uint x) pure nothrow @safe
// returns the maximum power of x that will fit in a ulong.
int highestPowerBelowUlongMax(uint x) pure nothrow @safe
{
- assert(x>1);
+ assert(x > 1, "x must be greater than 1");
static immutable ubyte [39] maxpwr = [ 63, 40, 31, 27, 24, 22, 21, 20, 19, 18,
17, 17, 16, 16, 15, 15, 15, 15, 14, 14,
14, 14, 13, 13, 13, 13, 13, 13, 13, 12,
@@ -1172,10 +1468,10 @@ int highestPowerBelowUlongMax(uint x) pure nothrow @safe
return 2;
}
-version (unittest)
+version (StdUnittest)
{
-int slowHighestPowerBelowUintMax(uint x) pure nothrow @safe
+private int slowHighestPowerBelowUintMax(uint x) pure nothrow @safe
{
int pwr = 1;
for (ulong q = x;x*q < cast(ulong) uint.max; )
@@ -1199,9 +1495,11 @@ int slowHighestPowerBelowUintMax(uint x) pure nothrow @safe
/* General unsigned subtraction routine for bigints.
* Sets result = x - y. If the result is negative, negative will be true.
+ * Returns:
+ * unique memory
*/
-BigDigit [] sub(const BigDigit [] x, const BigDigit [] y, bool *negative)
-pure nothrow
+BigDigit [] sub(const scope BigDigit [] x, const scope BigDigit [] y, bool *negative)
+pure nothrow @safe
{
if (x.length == y.length)
{
@@ -1255,8 +1553,12 @@ pure nothrow
}
-// return a + b
-BigDigit [] add(const BigDigit [] a, const BigDigit [] b) pure nothrow
+/*
+ * return a + b
+ * Returns:
+ * unique memory
+ */
+BigDigit [] add(const scope BigDigit [] a, const scope BigDigit [] b) pure nothrow @safe
{
const(BigDigit) [] x, y;
if (a.length < b.length)
@@ -1288,7 +1590,7 @@ BigDigit [] add(const BigDigit [] a, const BigDigit [] b) pure nothrow
/** return x + y
*/
-BigDigit [] addInt(const BigDigit[] x, ulong y) pure nothrow
+BigDigit [] addInt(const BigDigit[] x, ulong y) @safe pure nothrow
{
uint hi = cast(uint)(y >>> 32);
uint lo = cast(uint)(y& 0xFFFF_FFFF);
@@ -1315,7 +1617,7 @@ BigDigit [] addInt(const BigDigit[] x, ulong y) pure nothrow
/** Return x - y.
* x must be greater than y.
*/
-BigDigit [] subInt(const BigDigit[] x, ulong y) pure nothrow
+BigDigit [] subInt(const BigDigit[] x, ulong y) pure nothrow @safe
{
uint hi = cast(uint)(y >>> 32);
uint lo = cast(uint)(y & 0xFFFF_FFFF);
@@ -1340,12 +1642,13 @@ BigDigit [] subInt(const BigDigit[] x, ulong y) pure nothrow
*
*/
void mulInternal(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y)
- pure nothrow
+ pure nothrow @safe
{
import core.memory : GC;
- assert( result.length == x.length + y.length );
- assert( y.length > 0 );
- assert( x.length >= y.length);
+ assert( result.length == x.length + y.length,
+ "result array must have enough space to store computed result");
+ assert( y.length > 0, "y must not be empty");
+ assert( x.length >= y.length, "x must be greater or equal than y");
if (y.length <= KARATSUBALIMIT)
{
// Small multiplier, we'll just use the asm classic multiply.
@@ -1355,6 +1658,7 @@ void mulInternal(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y)
return;
}
+ immutable CACHELIMIT = getCacheLimit;
if (x.length + y.length < CACHELIMIT)
return mulSimple(result, x, y);
@@ -1402,59 +1706,81 @@ void mulInternal(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y)
auto extra = x.length % y.length;
auto maxchunk = chunksize + extra;
bool paddingY; // true = we're padding Y, false = we're padding X.
- if (extra * extra * 2 < y.length*y.length)
- {
- // The leftover bit is small enough that it should be incorporated
- // in the existing chunks.
- // Make all the chunks a tiny bit bigger
- // (We're padding y with zeros)
- chunksize += extra / numchunks;
- extra = x.length - chunksize*numchunks;
- // there will probably be a few left over.
- // Every chunk will either have size chunksize, or chunksize+1.
- maxchunk = chunksize + 1;
- paddingY = true;
- assert(chunksize + extra + chunksize *(numchunks-1) == x.length );
+ bool isExtraSmall = extra * extra * 2 < y.length * y.length;
+ if (numchunks == 1 && isExtraSmall)
+ {
+ // We divide (x_first_half * y) and (x_last_half * y)
+ // between 1.414:1 and 1.707:1 (1.707 = 1+1/sqrt(2)).
+ // (1.414 ~ 1.707)/2:1 is balanced.
+ BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(y.length) + y.length];
+ BigDigit [] partial = scratchbuff[$ - y.length .. $];
+ scratchbuff = scratchbuff[0 .. $ - y.length];
+ mulKaratsuba(result[0 .. half + y.length], y, x[0 .. half], scratchbuff);
+ partial[] = result[half .. half + y.length];
+ mulKaratsuba(result[half .. $], y, x[half .. $], scratchbuff);
+ BigDigit c = addAssignSimple(result[half .. half + y.length], partial);
+ if (c) multibyteIncrementAssign!('+')(result[half + y.length..$], c);
+ () @trusted { GC.free(scratchbuff.ptr); } ();
}
else
{
- // the extra bit is large enough that it's worth making a new chunk.
- // (This means we're padding x with zeros, when doing the first one).
- maxchunk = chunksize;
- ++numchunks;
- paddingY = false;
- assert(extra + chunksize *(numchunks-1) == x.length );
- }
- // We make the buffer a bit bigger so we have space for the partial sums.
- BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(maxchunk) + y.length];
- BigDigit [] partial = scratchbuff[$ - y.length .. $];
- size_t done; // how much of X have we done so far?
- if (paddingY)
- {
- // If the first chunk is bigger, do it first. We're padding y.
- mulKaratsuba(result[0 .. y.length + chunksize + (extra > 0 ? 1 : 0 )],
- x[0 .. chunksize + (extra>0?1:0)], y, scratchbuff);
- done = chunksize + (extra > 0 ? 1 : 0);
- if (extra) --extra;
- }
- else
- { // We're padding X. Begin with the extra bit.
- mulKaratsuba(result[0 .. y.length + extra], y, x[0 .. extra], scratchbuff);
- done = extra;
- extra = 0;
- }
- immutable basechunksize = chunksize;
- while (done < x.length)
- {
- chunksize = basechunksize + (extra > 0 ? 1 : 0);
- if (extra) --extra;
- partial[] = result[done .. done+y.length];
- mulKaratsuba(result[done .. done + y.length + chunksize],
- x[done .. done+chunksize], y, scratchbuff);
- addAssignSimple(result[done .. done + y.length + chunksize], partial);
- done += chunksize;
+ if (isExtraSmall)
+ {
+ // The leftover bit is small enough that it should be incorporated
+ // in the existing chunks.
+ // Make all the chunks a tiny bit bigger
+ // (We're padding y with zeros)
+ chunksize += extra / numchunks;
+ extra = x.length - chunksize*numchunks;
+ // there will probably be a few left over.
+ // Every chunk will either have size chunksize, or chunksize+1.
+ maxchunk = chunksize + 1;
+ paddingY = true;
+ assert(chunksize + extra + chunksize *(numchunks-1) == x.length,
+ "Unexpected size");
+ }
+ else
+ {
+ // the extra bit is large enough that it's worth making a new chunk.
+ // (This means we're padding x with zeros, when doing the first one).
+ maxchunk = chunksize;
+ ++numchunks;
+ paddingY = false;
+ assert(extra + chunksize *(numchunks-1) == x.length,
+ "Unexpected size");
+ }
+ // We make the buffer a bit bigger so we have space for the partial sums.
+ BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(maxchunk) + y.length];
+ BigDigit [] partial = scratchbuff[$ - y.length .. $];
+ scratchbuff = scratchbuff[0 .. $ - y.length];
+ size_t done; // how much of X have we done so far?
+ if (paddingY)
+ {
+ // If the first chunk is bigger, do it first. We're padding y.
+ mulKaratsuba(result[0 .. y.length + chunksize + (extra > 0 ? 1 : 0 )],
+ x[0 .. chunksize + (extra>0?1:0)], y, scratchbuff);
+ done = chunksize + (extra > 0 ? 1 : 0);
+ if (extra) --extra;
+ }
+ else
+ { // We're padding X. Begin with the extra bit.
+ mulKaratsuba(result[0 .. y.length + extra], y, x[0 .. extra], scratchbuff);
+ done = extra;
+ extra = 0;
+ }
+ immutable basechunksize = chunksize;
+ while (done < x.length)
+ {
+ chunksize = basechunksize + (extra > 0 ? 1 : 0);
+ if (extra) --extra;
+ partial[] = result[done .. done+y.length];
+ mulKaratsuba(result[done .. done + y.length + chunksize],
+ x[done .. done+chunksize], y, scratchbuff);
+ addAssignSimple(result[done .. done + y.length + chunksize], partial);
+ done += chunksize;
+ }
+ () @trusted { GC.free(scratchbuff.ptr); } ();
}
- () @trusted { GC.free(scratchbuff.ptr); } ();
}
else
{
@@ -1465,17 +1791,43 @@ void mulInternal(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y)
}
}
+// https://issues.dlang.org/show_bug.cgi?id=20493
+@safe unittest
+{
+ // the bug report has a testcase with very large numbers (~10^3800 and ~10^2300)
+ // the number itself isn't important, only the amount of digits, so we do a simpler
+ // multiplication of the same size, analogous to:
+ // 11111111 * 11111111 = 0123456787654321
+ // but instead of base 10, it's in base `BigDigit`
+
+ BigDigit[398] x = 1;
+ BigDigit[236] y = 1;
+ BigDigit[x.length + y.length] result;
+ mulInternal(result[], x[], y[]);
+
+ // create an array of the form [1, 2, ..., y.length, ..., y.length, y.length-1, ..., 1, 0]
+ BigDigit[x.length + y.length] expected = y.length;
+ foreach (BigDigit i; 0 .. y.length)
+ {
+ expected[i] = i+1;
+ expected[$-1-i] = i;
+ }
+
+ assert(result == expected);
+}
+
/** General unsigned squaring routine for BigInts.
* Sets result = x*x.
* NOTE: If the highest half-digit of x is zero, the highest digit of result will
* also be zero.
*/
-void squareInternal(BigDigit[] result, const BigDigit[] x) pure nothrow
+void squareInternal(BigDigit[] result, const BigDigit[] x) pure nothrow @safe
{
import core.memory : GC;
// Squaring is potentially half a multiply, plus add the squares of
// the diagonal elements.
- assert(result.length == 2*x.length);
+ assert(result.length == 2*x.length,
+ "result needs to have twice the capacity of x");
if (x.length <= KARATSUBASQUARELIMIT)
{
if (x.length == 1)
@@ -1496,13 +1848,15 @@ import core.bitop : bsr;
/// if remainder is null, only calculate quotient.
void divModInternal(BigDigit [] quotient, BigDigit[] remainder, const BigDigit [] u,
- const BigDigit [] v) pure nothrow
+ const BigDigit [] v) pure nothrow @safe
{
import core.memory : GC;
- assert(quotient.length == u.length - v.length + 1);
- assert(remainder == null || remainder.length == v.length);
- assert(v.length > 1);
- assert(u.length >= v.length);
+ assert(quotient.length == u.length - v.length + 1,
+ "Invalid quotient length");
+ assert(remainder == null || remainder.length == v.length,
+ "Invalid remainder");
+ assert(v.length > 1, "v must have more than 1 element");
+ assert(u.length >= v.length, "u must be as longer or longer than v");
// Normalize by shifting v left just enough so that
// its high-order bit is on, and shift u left the
@@ -1541,7 +1895,7 @@ void divModInternal(BigDigit [] quotient, BigDigit[] remainder, const BigDigit [
() @trusted { GC.free(un.ptr); GC.free(vn.ptr); } ();
}
-pure @system unittest
+pure @safe unittest
{
immutable(uint) [] u = [0, 0xFFFF_FFFE, 0x8000_0000];
immutable(uint) [] v = [0xFFFF_FFFF, 0x8000_0000];
@@ -1563,7 +1917,7 @@ private:
// every 8 digits.
// buff.length must be data.length*8 if separator is zero,
// or data.length*9 if separator is non-zero. It will be completely filled.
-char [] biguintToHex(char [] buff, const BigDigit [] data, char separator=0,
+char [] biguintToHex(scope return char [] buff, const scope BigDigit [] data, char separator=0,
LetterCase letterCase = LetterCase.upper) pure nothrow @safe
{
int x=0;
@@ -1613,10 +1967,10 @@ size_t biguintToOctal(char[] buff, const(BigDigit)[] data)
if (shift < 0)
{
// Some bits were carried over from previous word.
- assert(shift > -3);
+ assert(shift > -3, "shift must be greater than -3");
output(((bigdigit << -shift) | carry) & 0b111);
shift += 3;
- assert(shift > 0);
+ assert(shift > 0, "shift must be 1 or greater");
}
while (shift <= BigDigitBits - 3)
@@ -1631,13 +1985,13 @@ size_t biguintToOctal(char[] buff, const(BigDigit)[] data)
carry = (bigdigit >>> shift) & 0b11;
}
shift -= BigDigitBits;
- assert(shift >= -2 && shift <= 0);
+ assert(shift >= -2 && shift <= 0, "shift must in [-2,0]");
}
if (shift < 0)
{
// Last word had bits that haven't been output yet.
- assert(shift > -3);
+ assert(shift > -3, "Shift must be greater than -3");
output(carry);
}
@@ -1656,7 +2010,7 @@ size_t biguintToOctal(char[] buff, const(BigDigit)[] data)
* Returns:
* the lowest index of buff which was used.
*/
-size_t biguintToDecimal(char [] buff, BigDigit [] data) pure nothrow
+size_t biguintToDecimal(char [] buff, BigDigit [] data) pure nothrow @safe
{
ptrdiff_t sofar = buff.length;
// Might be better to divide by (10^38/2^32) since that gives 38 digits for
@@ -1701,9 +2055,10 @@ if (
in
{
static if (hasLength!Range)
- assert((data.length >= 2) || (data.length == 1 && s.length == 1));
+ assert((data.length >= 2) || (data.length == 1 && s.length == 1),
+ "data has a invalid length");
}
-body
+do
{
import std.conv : ConvException;
@@ -1837,26 +2192,27 @@ private:
// Classic 'schoolbook' multiplication.
void mulSimple(BigDigit[] result, const(BigDigit) [] left,
- const(BigDigit)[] right) pure nothrow
+ const(BigDigit)[] right) pure nothrow @safe
in
{
- assert(result.length == left.length + right.length);
- assert(right.length>1);
+ assert(result.length == left.length + right.length,
+ "Result must be able to store left + right");
+ assert(right.length>1, "right must not be empty");
}
-body
+do
{
result[left.length] = multibyteMul(result[0 .. left.length], left, right[0], 0);
multibyteMultiplyAccumulate(result[1..$], left, right[1..$]);
}
// Classic 'schoolbook' squaring
-void squareSimple(BigDigit[] result, const(BigDigit) [] x) pure nothrow
+void squareSimple(BigDigit[] result, const(BigDigit) [] x) pure nothrow @safe
in
{
- assert(result.length == 2*x.length);
- assert(x.length>1);
+ assert(result.length == 2*x.length, "result must be twice as long as x");
+ assert(x.length>1, "x must not be empty");
}
-body
+do
{
multibyteSquare(result, x);
}
@@ -1866,14 +2222,16 @@ body
// as the larger length.
// Returns carry (0 or 1).
uint addSimple(BigDigit[] result, const BigDigit [] left, const BigDigit [] right)
-pure nothrow
+pure nothrow @safe
in
{
- assert(result.length == left.length);
- assert(left.length >= right.length);
- assert(right.length>0);
+ assert(result.length == left.length,
+ "result and left must be of the same length");
+ assert(left.length >= right.length,
+ "left must be longer or of equal length to right");
+ assert(right.length > 0, "right must not be empty");
}
-body
+do
{
uint carry = multibyteAdd(result[0 .. right.length],
left[0 .. right.length], right, 0);
@@ -1891,11 +2249,13 @@ BigDigit subSimple(BigDigit [] result,const(BigDigit) [] left,
const(BigDigit) [] right) pure nothrow
in
{
- assert(result.length == left.length);
- assert(left.length >= right.length);
- assert(right.length>0);
+ assert(result.length == left.length,
+ "result and left must be of the same length");
+ assert(left.length >= right.length,
+ "left must be longer or of equal length to right");
+ assert(right.length > 0, "right must not be empty");
}
-body
+do
{
BigDigit carry = multibyteSub(result[0 .. right.length],
left[0 .. right.length], right, 0);
@@ -1912,9 +2272,10 @@ body
* Returns carry = 1 if result was less than right.
*/
BigDigit subAssignSimple(BigDigit [] result, const(BigDigit) [] right)
-pure nothrow
+pure nothrow @safe
{
- assert(result.length >= right.length);
+ assert(result.length >= right.length,
+ "result must be longer or of equal length to right");
uint c = multibyteSub(result[0 .. right.length], result[0 .. right.length], right, 0);
if (c && result.length > right.length)
c = multibyteIncrementAssign!('-')(result[right.length .. $], c);
@@ -1924,9 +2285,10 @@ pure nothrow
/* result = result + right
*/
BigDigit addAssignSimple(BigDigit [] result, const(BigDigit) [] right)
-pure nothrow
+pure nothrow @safe
{
- assert(result.length >= right.length);
+ assert(result.length >= right.length,
+ "result must be longer or of equal length to right");
uint c = multibyteAdd(result[0 .. right.length], result[0 .. right.length], right, 0);
if (c && result.length > right.length)
c = multibyteIncrementAssign!('+')(result[right.length .. $], c);
@@ -1936,7 +2298,7 @@ pure nothrow
/* performs result += wantSub? - right : right;
*/
BigDigit addOrSubAssignSimple(BigDigit [] result, const(BigDigit) [] right,
- bool wantSub) pure nothrow
+ bool wantSub) pure nothrow @safe
{
if (wantSub)
return subAssignSimple(result, right);
@@ -1946,9 +2308,10 @@ BigDigit addOrSubAssignSimple(BigDigit [] result, const(BigDigit) [] right,
// return true if x<y, considering leading zeros
-bool less(const(BigDigit)[] x, const(BigDigit)[] y) pure nothrow
+bool less(const(BigDigit)[] x, const(BigDigit)[] y) pure nothrow @safe
{
- assert(x.length >= y.length);
+ assert(x.length >= y.length,
+ "x must be longer or of equal length to y");
auto k = x.length-1;
while (x[k]==0 && k >= y.length)
--k;
@@ -1961,9 +2324,10 @@ bool less(const(BigDigit)[] x, const(BigDigit)[] y) pure nothrow
// Set result = abs(x-y), return true if result is negative(x<y), false if x <= y.
bool inplaceSub(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y)
- pure nothrow
+ pure nothrow @safe
{
- assert(result.length == (x.length >= y.length) ? x.length : y.length);
+ assert(result.length == ((x.length >= y.length) ? x.length : y.length),
+ "result must capable to store the maximum of x and y");
size_t minlen;
bool negative;
@@ -2000,10 +2364,12 @@ bool inplaceSub(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y)
/* Determine how much space is required for the temporaries
* when performing a Karatsuba multiplication.
+ * TODO: determining a tight bound is non-trivial and depends on KARATSUBALIMIT, see:
+ * https://issues.dlang.org/show_bug.cgi?id=20493
*/
size_t karatsubaRequiredBuffSize(size_t xlen) pure nothrow @safe
{
- return xlen <= KARATSUBALIMIT ? 0 : 2*xlen; // - KARATSUBALIMIT+2;
+ return xlen <= KARATSUBALIMIT ? 0 : (xlen * 9) / 4;
}
/* Sets result = x*y, using Karatsuba multiplication.
@@ -2018,11 +2384,12 @@ size_t karatsubaRequiredBuffSize(size_t xlen) pure nothrow @safe
* scratchbuff An array long enough to store all the temporaries. Will be destroyed.
*/
void mulKaratsuba(BigDigit [] result, const(BigDigit) [] x,
- const(BigDigit)[] y, BigDigit [] scratchbuff) pure nothrow
+ const(BigDigit)[] y, BigDigit [] scratchbuff) pure nothrow @safe
{
- assert(x.length >= y.length);
- assert(result.length < uint.max, "Operands too large");
- assert(result.length == x.length + y.length);
+ assert(x.length >= y.length, "x must be greater or equal to y");
+ assert(result.length < uint.max, "Operands too large");
+ assert(result.length == x.length + y.length,
+ "result must be as large as x + y");
if (x.length <= KARATSUBALIMIT)
{
return mulSimple(result, x, y);
@@ -2123,12 +2490,13 @@ void mulKaratsuba(BigDigit [] result, const(BigDigit) [] x,
}
void squareKaratsuba(BigDigit [] result, const BigDigit [] x,
- BigDigit [] scratchbuff) pure nothrow
+ BigDigit [] scratchbuff) pure nothrow @safe
{
// See mulKaratsuba for implementation comments.
// Squaring is simpler, since it never gets asymmetric.
assert(result.length < uint.max, "Operands too large");
- assert(result.length == 2*x.length);
+ assert(result.length == 2*x.length,
+ "result must be twice the length of x");
if (x.length <= KARATSUBASQUARELIMIT)
{
return squareSimple(result, x);
@@ -2180,13 +2548,14 @@ void squareKaratsuba(BigDigit [] result, const BigDigit [] x,
* u[0 .. v.length] holds the remainder.
*/
void schoolbookDivMod(BigDigit [] quotient, BigDigit [] u, in BigDigit [] v)
- pure nothrow
+ pure nothrow @safe
{
- assert(quotient.length == u.length - v.length);
- assert(v.length > 1);
- assert(u.length >= v.length);
- assert((v[$-1]&0x8000_0000)!=0);
- assert(u[$-1] < v[$-1]);
+ assert(quotient.length == u.length - v.length,
+ "quotient has wrong length");
+ assert(v.length > 1, "v must not be empty");
+ assert(u.length >= v.length, "u must be larger or equal to v");
+ assert((v[$ - 1] & 0x8000_0000) != 0, "Invalid value at v[$ - 1]");
+ assert(u[$ - 1] < v[$ - 1], "u[$ - 1] must be less than v[$ - 1]");
// BUG: This code only works if BigDigit is uint.
uint vhi = v[$-1];
uint vlo = v[$-2];
@@ -2208,7 +2577,7 @@ void schoolbookDivMod(BigDigit [] quotient, BigDigit [] u, in BigDigit [] v)
{
// Note: On DMD, this is only ~10% faster than the non-asm code.
uint *p = &u[j + v.length - 1];
- asm pure nothrow
+ asm pure nothrow @trusted
{
mov EAX, p;
mov EDX, [EAX+4];
@@ -2307,7 +2676,8 @@ private:
size_t highestDifferentDigit(const BigDigit [] left, const BigDigit [] right)
pure nothrow @nogc @safe
{
- assert(left.length == right.length);
+ assert(left.length == right.length,
+ "left have a length equal to that of right");
for (ptrdiff_t i = left.length - 1; i>0; --i)
{
if (left[i] != right[i])
@@ -2323,7 +2693,7 @@ int firstNonZeroDigit(const BigDigit [] x) pure nothrow @nogc @safe
while (x[k]==0)
{
++k;
- assert(k<x.length);
+ assert(k < x.length, "k must be less than x.length");
}
return k;
}
@@ -2354,26 +2724,30 @@ Returns:
*/
void recursiveDivMod(BigDigit[] quotient, BigDigit[] u, const(BigDigit)[] v,
BigDigit[] scratch, bool mayOverflow = false)
- pure nothrow
+ pure nothrow @safe
in
{
// v must be normalized
- assert(v.length > 1);
- assert((v[$ - 1] & 0x8000_0000) != 0);
- assert(!(u[$ - 1] & 0x8000_0000));
- assert(quotient.length == u.length - v.length);
+ assert(v.length > 1, "v must not be empty");
+ assert((v[$ - 1] & 0x8000_0000) != 0, "Invalid value at v[$ - 1]");
+ assert(!(u[$ - 1] & 0x8000_0000), "Invalid value at u[$ - 1]");
+ assert(quotient.length == u.length - v.length,
+ "quotient must be of equal length of u - v");
if (mayOverflow)
{
- assert(u[$-1] == 0);
- assert(u[$-2] & 0x8000_0000);
+ assert(u[$-1] == 0, "Invalid value at u[$ - 1]");
+ assert(u[$-2] & 0x8000_0000, "Invalid value at u[$ - 2]");
}
// Must be symmetric. Use block schoolbook division if not.
- assert((mayOverflow ? u.length-1 : u.length) <= 2 * v.length);
- assert((mayOverflow ? u.length-1 : u.length) >= v.length);
- assert(scratch.length >= quotient.length + (mayOverflow ? 0 : 1));
+ assert((mayOverflow ? u.length-1 : u.length) <= 2 * v.length,
+ "Invalid length of u");
+ assert((mayOverflow ? u.length-1 : u.length) >= v.length,
+ "Invalid length of u");
+ assert(scratch.length >= quotient.length + (mayOverflow ? 0 : 1),
+ "Invalid quotient length");
}
-body
+do
{
if (quotient.length < FASTDIVLIMIT)
{
@@ -2444,9 +2818,9 @@ body
// Needs (quot.length * k) scratch space to store the result of the multiply.
void adjustRemainder(BigDigit[] quot, BigDigit[] rem, const(BigDigit)[] v,
ptrdiff_t k,
- BigDigit[] scratch, bool mayOverflow = false) pure nothrow
+ BigDigit[] scratch, bool mayOverflow = false) pure nothrow @safe
{
- assert(rem.length == v.length);
+ assert(rem.length == v.length, "rem must be as long as v");
mulInternal(scratch, quot, v[0 .. k]);
uint carry = 0;
if (mayOverflow)
@@ -2462,14 +2836,15 @@ void adjustRemainder(BigDigit[] quot, BigDigit[] rem, const(BigDigit)[] v,
// Cope with unbalanced division by performing block schoolbook division.
void blockDivMod(BigDigit [] quotient, BigDigit [] u, in BigDigit [] v)
-pure nothrow
+pure nothrow @safe
{
import core.memory : GC;
- assert(quotient.length == u.length - v.length);
- assert(v.length > 1);
- assert(u.length >= v.length);
- assert((v[$-1] & 0x8000_0000)!=0);
- assert((u[$-1] & 0x8000_0000)==0);
+ assert(quotient.length == u.length - v.length,
+ "quotient must be of equal length of u - v");
+ assert(v.length > 1, "v must not be empty");
+ assert(u.length >= v.length, "u must be longer or of equal length as v");
+ assert((v[$-1] & 0x8000_0000)!=0, "Invalid value at v[$ - 1]");
+ assert((u[$-1] & 0x8000_0000)==0, "Invalid value at u[$ - 1]");
BigDigit [] scratch = new BigDigit[v.length + 1];
// Perform block schoolbook division, with 'v.length' blocks.
@@ -2487,7 +2862,7 @@ pure nothrow
u[m - v.length .. m + v.length + (mayOverflow? 1: 0)], v, scratch, mayOverflow);
if (mayOverflow)
{
- assert(quotient[m] == 0);
+ assert(quotient[m] == 0, "quotient must not be 0");
quotient[m] = saveq;
}
m -= v.length;
@@ -2498,18 +2873,21 @@ pure nothrow
@system unittest
{
- import core.stdc.stdio;
-
- void printBiguint(const uint [] data)
+ version (none)
{
- char [] buff = biguintToHex(new char[data.length*9], data, '_');
- printf("%.*s\n", cast(int) buff.length, buff.ptr);
- }
+ import core.stdc.stdio;
- void printDecimalBigUint(BigUint data)
- {
- auto str = data.toDecimalString(0);
- printf("%.*s\n", cast(int) str.length, str.ptr);
+ void printBiguint(const uint [] data)
+ {
+ char [] buff = biguintToHex(new char[data.length*9], data, '_');
+ printf("%.*s\n", cast(int) buff.length, buff.ptr);
+ }
+
+ void printDecimalBigUint(BigUint data)
+ {
+ auto str = data.toDecimalString(0);
+ printf("%.*s\n", cast(int) str.length, str.ptr);
+ }
}
uint [] a, b;
diff --git a/libphobos/src/std/internal/math/biguintnoasm.d b/libphobos/src/std/internal/math/biguintnoasm.d
index aea1d50..2b2b5f1 100644
--- a/libphobos/src/std/internal/math/biguintnoasm.d
+++ b/libphobos/src/std/internal/math/biguintnoasm.d
@@ -61,10 +61,10 @@ uint multibyteAddSub(char op)(uint[] dest, const(uint) [] src1,
}
c[19]=0x3333_3333;
uint carry = multibyteAddSub!('+')(c[0 .. 18], b[0 .. 18], a[0 .. 18], 0);
- assert(c[0]==0x8000_0003);
- assert(c[1]==4);
- assert(c[19]==0x3333_3333); // check for overrun
- assert(carry == 1);
+ assert(c[0]==0x8000_0003, "c[0] has invalid value");
+ assert(c[1]==4, "c[1] must be for");
+ assert(c[19]==0x3333_3333, "c[19] has invalid value"); // check for overrun
+ assert(carry == 1, "carry must be 1");
for (size_t i = 0; i < a.length; ++i)
{
a[i] = b[i] = c[i] = 0;
@@ -75,10 +75,10 @@ uint multibyteAddSub(char op)(uint[] dest, const(uint) [] src1,
b[10]=0x1D950C84;
a[5] =0x44444444;
carry = multibyteAddSub!('-')(a[0 .. 12], a[0 .. 12], b[0 .. 12], 0);
- assert(a[11] == 0);
+ assert(a[11] == 0, "a[11] must be 0");
for (size_t i = 0; i < 10; ++i)
if (i != 5)
- assert(a[i] == 0);
+ assert(a[i] == 0, "a[1] must be 0");
for (size_t q = 3; q < 36; ++q)
{
@@ -89,7 +89,7 @@ uint multibyteAddSub(char op)(uint[] dest, const(uint) [] src1,
a[q-2]=0x040000;
b[q-2]=0x040000;
carry = multibyteAddSub!('-')(a[0 .. q], a[0 .. q], b[0 .. q], 0);
- assert(a[q-2]==0);
+ assert(a[q-2]==0, "a[q-2] must be 0");
}
}
@@ -193,7 +193,7 @@ void multibyteShr(uint [] dest, const(uint) [] src, uint numbits)
uint multibyteMul(uint[] dest, const(uint)[] src, uint multiplier, uint carry)
pure @nogc @safe
{
- assert(dest.length == src.length);
+ assert(dest.length == src.length, "dest and src must have the same length");
ulong c = carry;
for (size_t i = 0; i < src.length; ++i)
{
@@ -220,7 +220,7 @@ uint multibyteMul(uint[] dest, const(uint)[] src, uint multiplier, uint carry)
uint multibyteMulAdd(char op)(uint [] dest, const(uint)[] src,
uint multiplier, uint carry) pure @nogc @safe
{
- assert(dest.length == src.length);
+ assert(dest.length == src.length, "dest and src must have the same length");
ulong c = carry;
for (size_t i = 0; i < src.length; ++i)
{
diff --git a/libphobos/src/std/internal/math/errorfunction.d b/libphobos/src/std/internal/math/errorfunction.d
index 4012e64..8894ffb 100644
--- a/libphobos/src/std/internal/math/errorfunction.d
+++ b/libphobos/src/std/internal/math/errorfunction.d
@@ -24,6 +24,7 @@
*/
module std.internal.math.errorfunction;
import std.math;
+import core.math : fabs, sqrt;
pure:
nothrow:
@@ -50,16 +51,16 @@ private {
/* erfc(x) = exp(-x^2) P(1/x)/Q(1/x)
1/8 <= 1/x <= 1
Peak relative error 5.8e-21 */
-immutable real[10] P = [ -0x1.30dfa809b3cc6676p-17, 0x1.38637cd0913c0288p+18,
- 0x1.2f015e047b4476bp+22, 0x1.24726f46aa9ab08p+25, 0x1.64b13c6395dc9c26p+27,
- 0x1.294c93046ad55b5p+29, 0x1.5962a82f92576dap+30, 0x1.11a709299faba04ap+31,
- 0x1.11028065b087be46p+31, 0x1.0d8ef40735b097ep+30
+immutable real[10] P = [ -0x1.30dfa809b3cc6676p-17L, 0x1.38637cd0913c0288p+18L,
+ 0x1.2f015e047b4476bp+22L, 0x1.24726f46aa9ab08p+25L, 0x1.64b13c6395dc9c26p+27L,
+ 0x1.294c93046ad55b5p+29L, 0x1.5962a82f92576dap+30L, 0x1.11a709299faba04ap+31L,
+ 0x1.11028065b087be46p+31L, 0x1.0d8ef40735b097ep+30L
];
-immutable real[11] Q = [ 0x1.14d8e2a72dec49f4p+19, 0x1.0c880ff467626e1p+23,
- 0x1.04417ef060b58996p+26, 0x1.404e61ba86df4ebap+28, 0x1.0f81887bc82b873ap+30,
- 0x1.4552a5e39fb49322p+31, 0x1.11779a0ceb2a01cep+32, 0x1.3544dd691b5b1d5cp+32,
- 0x1.a91781f12251f02ep+31, 0x1.0d8ef3da605a1c86p+30, 1.0
+immutable real[11] Q = [ 0x1.14d8e2a72dec49f4p+19L, 0x1.0c880ff467626e1p+23L,
+ 0x1.04417ef060b58996p+26L, 0x1.404e61ba86df4ebap+28L, 0x1.0f81887bc82b873ap+30L,
+ 0x1.4552a5e39fb49322p+31L, 0x1.11779a0ceb2a01cep+32L, 0x1.3544dd691b5b1d5cp+32L,
+ 0x1.a91781f12251f02ep+31L, 0x1.0d8ef3da605a1c86p+30L, 1.0L
];
// For 128 bit quadruple-precision floats, we use a higher-precision implementation
@@ -120,7 +121,7 @@ static if (isIEEEQuadruple)
1.367697521219069280358984081407807931847E1L,
2.276988395995528495055594829206582732682E1L,
7.647745753648996559837591812375456641163E-1L,
- 1.0
+ 1.0L
];
// erfc(0.375) = C14a + C14b to extra precision.
@@ -150,7 +151,7 @@ static if (isIEEEQuadruple)
2.628752920321455606558942309396855629459E1L,
2.455649035885114308978333741080991380610E1L,
1.378826653595128464383127836412100939126E0L,
- 1.0
+ 1.0L
];
// erfc(0.5) = C15a + C15b to extra precision.
immutable real C15a = 0.4794921875L;
@@ -179,7 +180,7 @@ static if (isIEEEQuadruple)
4.465334221323222943418085830026979293091E1L,
2.612723259683205928103787842214809134746E1L,
2.341526751185244109722204018543276124997E0L,
- 1.0
+ 1.0L
];
// erfc(0.625) = C16a + C16b to extra precision.
immutable real C16a = 0.3767547607421875L;
@@ -208,7 +209,7 @@ static if (isIEEEQuadruple)
5.555800830216764702779238020065345401144E1L,
2.646215470959050279430447295801291168941E1L,
2.984905282103517497081766758550112011265E0L,
- 1.0
+ 1.0L
];
// erfc(0.75) = C17a + C17b to extra precision.
immutable real C17a = 0.2888336181640625L;
@@ -238,7 +239,7 @@ static if (isIEEEQuadruple)
5.998153487868943708236273854747564557632E1L,
2.657695108438628847733050476209037025318E1L,
3.252140524394421868923289114410336976512E0L,
- 1.0
+ 1.0L
];
// erfc(0.875) = C18a + C18b to extra precision.
@@ -268,7 +269,7 @@ static if (isIEEEQuadruple)
6.868976819510254139741559102693828237440E1L,
2.801505816247677193480190483913753613630E1L,
3.604439909194350263552750347742663954481E0L,
- 1.0
+ 1.0L
];
// erfc(1.0) = C19a + C19b to extra precision.
@@ -298,7 +299,7 @@ static if (isIEEEQuadruple)
8.848641738570783406484348434387611713070E1L,
3.132269062552392974833215844236160958502E1L,
4.430131663290563523933419966185230513168E0L,
- 1.0
+ 1.0L
];
// erfc(1.125) = C20a + C20b to extra precision.
@@ -604,26 +605,26 @@ else
/* erfc(x) = exp(-x^2) 1/x R(1/x^2) / S(1/x^2)
1/128 <= 1/x < 1/8
Peak relative error 1.9e-21 */
- immutable real[5] R = [ 0x1.b9f6d8b78e22459ep-6, 0x1.1b84686b0a4ea43ap-1,
- 0x1.b8f6aebe96000c2ap+1, 0x1.cb1dbedac27c8ec2p+2, 0x1.cf885f8f572a4c14p+1
+ immutable real[5] R = [ 0x1.b9f6d8b78e22459ep-6L, 0x1.1b84686b0a4ea43ap-1L,
+ 0x1.b8f6aebe96000c2ap+1L, 0x1.cb1dbedac27c8ec2p+2L, 0x1.cf885f8f572a4c14p+1L
];
immutable real[6] S = [
- 0x1.87ae3cae5f65eb5ep-5, 0x1.01616f266f306d08p+0, 0x1.a4abe0411eed6c22p+2,
- 0x1.eac9ce3da600abaap+3, 0x1.5752a9ac2faebbccp+3, 1.0
+ 0x1.87ae3cae5f65eb5ep-5L, 0x1.01616f266f306d08p+0L, 0x1.a4abe0411eed6c22p+2L,
+ 0x1.eac9ce3da600abaap+3L, 0x1.5752a9ac2faebbccp+3L, 1.0L
];
/* erf(x) = x P(x^2)/Q(x^2)
0 <= x <= 1
Peak relative error 7.6e-23 */
- immutable real[7] T = [ 0x1.0da01654d757888cp+20, 0x1.2eb7497bc8b4f4acp+17,
- 0x1.79078c19530f72a8p+15, 0x1.4eaf2126c0b2c23p+11, 0x1.1f2ea81c9d272a2ep+8,
- 0x1.59ca6e2d866e625p+2, 0x1.c188e0b67435faf4p-4
+ immutable real[7] T = [ 0x1.0da01654d757888cp+20L, 0x1.2eb7497bc8b4f4acp+17L,
+ 0x1.79078c19530f72a8p+15L, 0x1.4eaf2126c0b2c23p+11L, 0x1.1f2ea81c9d272a2ep+8L,
+ 0x1.59ca6e2d866e625p+2L, 0x1.c188e0b67435faf4p-4L
];
- immutable real[7] U = [ 0x1.dde6025c395ae34ep+19, 0x1.c4bc8b6235df35aap+18,
- 0x1.8465900e88b6903ap+16, 0x1.855877093959ffdp+13, 0x1.e5c44395625ee358p+9,
- 0x1.6a0fed103f1c68a6p+5, 1.0
+ immutable real[7] U = [ 0x1.dde6025c395ae34ep+19L, 0x1.c4bc8b6235df35aap+18L,
+ 0x1.8465900e88b6903ap+16L, 0x1.855877093959ffdp+13L, 0x1.e5c44395625ee358p+9L,
+ 0x1.6a0fed103f1c68a6p+5L, 1.0L
];
}
}
@@ -835,7 +836,7 @@ real erf(real x)
return -1.0;
if (x == real.infinity)
return 1.0;
- immutable ax = abs(x);
+ immutable ax = fabs(x);
if (ax > 1.0L)
return 1.0L - erfc(x);
@@ -867,16 +868,16 @@ real erf(real x)
@safe unittest
{
// High resolution test points.
- enum real erfc0_250 = 0.723663330078125 + 1.0279753638067014931732235184287934646022E-5;
- enum real erfc0_375 = 0.5958709716796875 + 1.2118885490201676174914080878232469565953E-5;
- enum real erfc0_500 = 0.4794921875 + 7.9346869534623172533461080354712635484242E-6;
- enum real erfc0_625 = 0.3767547607421875 + 4.3570693945275513594941232097252997287766E-6;
- enum real erfc0_750 = 0.2888336181640625 + 1.0748182422368401062165408589222625794046E-5;
- enum real erfc0_875 = 0.215911865234375 + 1.3073705765341685464282101150637224028267E-5;
- enum real erfc1_000 = 0.15728759765625 + 1.1609394035130658779364917390740703933002E-5;
- enum real erfc1_125 = 0.111602783203125 + 8.9850951672359304215530728365232161564636E-6;
+ enum real erfc0_250 = 0.723663330078125L + 1.0279753638067014931732235184287934646022E-5L;
+ enum real erfc0_375 = 0.5958709716796875L + 1.2118885490201676174914080878232469565953E-5L;
+ enum real erfc0_500 = 0.4794921875L + 7.9346869534623172533461080354712635484242E-6L;
+ enum real erfc0_625 = 0.3767547607421875L + 4.3570693945275513594941232097252997287766E-6L;
+ enum real erfc0_750 = 0.2888336181640625L + 1.0748182422368401062165408589222625794046E-5L;
+ enum real erfc0_875 = 0.215911865234375L + 1.3073705765341685464282101150637224028267E-5L;
+ enum real erfc1_000 = 0.15728759765625L + 1.1609394035130658779364917390740703933002E-5L;
+ enum real erfc1_125 = 0.111602783203125L + 8.9850951672359304215530728365232161564636E-6L;
- enum real erf0_875 = (1-0.215911865234375) - 1.3073705765341685464282101150637224028267E-5;
+ enum real erf0_875 = (1-0.215911865234375L) - 1.3073705765341685464282101150637224028267E-5L;
static bool isNaNWithPayload(real x, ulong payload) @safe pure nothrow @nogc
{
@@ -931,7 +932,7 @@ real expx2(real x, int sign)
const real M = 32_768.0;
const real MINV = 3.0517578125e-5L;
- x = abs(x);
+ x = fabs(x);
if (sign < 0)
x = -x;
@@ -984,7 +985,7 @@ Journal of Statistical Software <b>11</b>, (July 2004).
real normalDistributionImpl(real a)
{
real x = a * SQRT1_2;
- real z = abs(x);
+ real z = fabs(x);
if ( z < 1.0 )
return 0.5L + 0.5L * erf(x);
@@ -1002,7 +1003,7 @@ real normalDistributionImpl(real a)
@safe unittest
{
-assert(fabs(normalDistributionImpl(1L) - (0.841344746068543))< 0.0000000000000005);
+assert(fabs(normalDistributionImpl(1L) - (0.841344746068543L)) < 0.0000000000000005L);
assert(isIdentical(normalDistributionImpl(NaN(0x325)), NaN(0x325)));
}
@@ -1024,56 +1025,56 @@ real normalDistributionInvImpl(real p)
in {
assert(p >= 0.0L && p <= 1.0L, "Domain error");
}
-body
+do
{
static immutable real[8] P0 =
-[ -0x1.758f4d969484bfdcp-7, 0x1.53cee17a59259dd2p-3,
- -0x1.ea01e4400a9427a2p-1, 0x1.61f7504a0105341ap+1, -0x1.09475a594d0399f6p+2,
- 0x1.7c59e7a0df99e3e2p+1, -0x1.87a81da52edcdf14p-1, 0x1.1fb149fd3f83600cp-7
+[ -0x1.758f4d969484bfdcp-7L, 0x1.53cee17a59259dd2p-3L,
+ -0x1.ea01e4400a9427a2p-1L, 0x1.61f7504a0105341ap+1L, -0x1.09475a594d0399f6p+2L,
+ 0x1.7c59e7a0df99e3e2p+1L, -0x1.87a81da52edcdf14p-1L, 0x1.1fb149fd3f83600cp-7L
];
static immutable real[8] Q0 =
-[ -0x1.64b92ae791e64bb2p-7, 0x1.7585c7d597298286p-3,
- -0x1.40011be4f7591ce6p+0, 0x1.1fc067d8430a425ep+2, -0x1.21008ffb1e7ccdf2p+3,
- 0x1.3d1581cf9bc12fccp+3, -0x1.53723a89fd8f083cp+2, 1.0
+[ -0x1.64b92ae791e64bb2p-7L, 0x1.7585c7d597298286p-3L,
+ -0x1.40011be4f7591ce6p+0L, 0x1.1fc067d8430a425ep+2L, -0x1.21008ffb1e7ccdf2p+3L,
+ 0x1.3d1581cf9bc12fccp+3L, -0x1.53723a89fd8f083cp+2L, 1.0L
];
static immutable real[10] P1 =
-[ 0x1.20ceea49ea142f12p-13, 0x1.cbe8a7267aea80bp-7,
- 0x1.79fea765aa787c48p-2, 0x1.d1f59faa1f4c4864p+1, 0x1.1c22e426a013bb96p+4,
- 0x1.a8675a0c51ef3202p+5, 0x1.75782c4f83614164p+6, 0x1.7a2f3d90948f1666p+6,
- 0x1.5cd116ee4c088c3ap+5, 0x1.1361e3eb6e3cc20ap+2
+[ 0x1.20ceea49ea142f12p-13L, 0x1.cbe8a7267aea80bp-7L,
+ 0x1.79fea765aa787c48p-2L, 0x1.d1f59faa1f4c4864p+1L, 0x1.1c22e426a013bb96p+4L,
+ 0x1.a8675a0c51ef3202p+5L, 0x1.75782c4f83614164p+6L, 0x1.7a2f3d90948f1666p+6L,
+ 0x1.5cd116ee4c088c3ap+5L, 0x1.1361e3eb6e3cc20ap+2L
];
static immutable real[10] Q1 =
-[ 0x1.3a4ce1406cea98fap-13, 0x1.f45332623335cda2p-7,
- 0x1.98f28bbd4b98db1p-2, 0x1.ec3b24f9c698091cp+1, 0x1.1cc56ecda7cf58e4p+4,
- 0x1.92c6f7376bf8c058p+5, 0x1.4154c25aa47519b4p+6, 0x1.1b321d3b927849eap+6,
- 0x1.403a5f5a4ce7b202p+4, 1.0
+[ 0x1.3a4ce1406cea98fap-13L, 0x1.f45332623335cda2p-7L,
+ 0x1.98f28bbd4b98db1p-2L, 0x1.ec3b24f9c698091cp+1L, 0x1.1cc56ecda7cf58e4p+4L,
+ 0x1.92c6f7376bf8c058p+5L, 0x1.4154c25aa47519b4p+6L, 0x1.1b321d3b927849eap+6L,
+ 0x1.403a5f5a4ce7b202p+4L, 1.0L
];
static immutable real[8] P2 =
-[ 0x1.8c124a850116a6d8p-21, 0x1.534abda3c2fb90bap-13,
- 0x1.29a055ec93a4718cp-7, 0x1.6468e98aad6dd474p-3, 0x1.3dab2ef4c67a601cp+0,
- 0x1.e1fb3a1e70c67464p+1, 0x1.b6cce8035ff57b02p+2, 0x1.9f4c9e749ff35f62p+1
+[ 0x1.8c124a850116a6d8p-21L, 0x1.534abda3c2fb90bap-13L,
+ 0x1.29a055ec93a4718cp-7L, 0x1.6468e98aad6dd474p-3L, 0x1.3dab2ef4c67a601cp+0L,
+ 0x1.e1fb3a1e70c67464p+1L, 0x1.b6cce8035ff57b02p+2L, 0x1.9f4c9e749ff35f62p+1L
];
static immutable real[8] Q2 =
-[ 0x1.af03f4fc0655e006p-21, 0x1.713192048d11fb2p-13,
- 0x1.4357e5bbf5fef536p-7, 0x1.7fdac8749985d43cp-3, 0x1.4a080c813a2d8e84p+0,
- 0x1.c3a4b423cdb41bdap+1, 0x1.8160694e24b5557ap+2, 1.0
+[ 0x1.af03f4fc0655e006p-21L, 0x1.713192048d11fb2p-13L,
+ 0x1.4357e5bbf5fef536p-7L, 0x1.7fdac8749985d43cp-3L, 0x1.4a080c813a2d8e84p+0L,
+ 0x1.c3a4b423cdb41bdap+1L, 0x1.8160694e24b5557ap+2L, 1.0L
];
static immutable real[8] P3 =
-[ -0x1.55da447ae3806168p-34, -0x1.145635641f8778a6p-24,
- -0x1.abf46d6b48040128p-17, -0x1.7da550945da790fcp-11, -0x1.aa0b2a31157775fap-8,
- 0x1.b11d97522eed26bcp-3, 0x1.1106d22f9ae89238p+1, 0x1.029a358e1e630f64p+1
+[ -0x1.55da447ae3806168p-34L, -0x1.145635641f8778a6p-24L,
+ -0x1.abf46d6b48040128p-17L, -0x1.7da550945da790fcp-11L, -0x1.aa0b2a31157775fap-8L,
+ 0x1.b11d97522eed26bcp-3L, 0x1.1106d22f9ae89238p+1L, 0x1.029a358e1e630f64p+1L
];
static immutable real[8] Q3 =
-[ -0x1.74022dd5523e6f84p-34, -0x1.2cb60d61e29ee836p-24,
- -0x1.d19e6ec03a85e556p-17, -0x1.9ea2a7b4422f6502p-11, -0x1.c54b1e852f107162p-8,
- 0x1.e05268dd3c07989ep-3, 0x1.239c6aff14afbf82p+1, 1.0
+[ -0x1.74022dd5523e6f84p-34L, -0x1.2cb60d61e29ee836p-24L,
+ -0x1.d19e6ec03a85e556p-17L, -0x1.9ea2a7b4422f6502p-11L, -0x1.c54b1e852f107162p-8L,
+ 0x1.e05268dd3c07989ep-3L, 0x1.239c6aff14afbf82p+1L, 1.0L
];
if (p <= 0.0L || p >= 1.0L)
@@ -1130,9 +1131,9 @@ static immutable real[8] Q3 =
{
// TODO: Use verified test points.
// The values below are from Excel 2003.
- assert(fabs(normalDistributionInvImpl(0.001) - (-3.09023230616779))< 0.00000000000005);
- assert(fabs(normalDistributionInvImpl(1e-50) - (-14.9333375347885))< 0.00000000000005);
- assert(feqrel(normalDistributionInvImpl(0.999), -normalDistributionInvImpl(0.001)) > real.mant_dig-6);
+ assert(fabs(normalDistributionInvImpl(0.001) - (-3.09023230616779L)) < 0.00000000000005L);
+ assert(fabs(normalDistributionInvImpl(1e-50) - (-14.9333375347885L)) < 0.00000000000005L);
+ assert(feqrel(normalDistributionInvImpl(0.999L), -normalDistributionInvImpl(0.001L)) > real.mant_dig-6);
// Excel 2003 gets all the following values wrong!
assert(normalDistributionInvImpl(0.0) == -real.infinity);
@@ -1141,5 +1142,5 @@ static immutable real[8] Q3 =
// (Excel 2003 returns norminv(p) = -30 for all p < 1e-200).
// The value tested here is the one the function returned in Jan 2006.
real unknown1 = normalDistributionInvImpl(1e-250L);
- assert( fabs(unknown1 -(-33.79958617269L) ) < 0.00000005);
+ assert( fabs(unknown1 -(-33.79958617269L) ) < 0.00000005L);
}
diff --git a/libphobos/src/std/internal/math/gammafunction.d b/libphobos/src/std/internal/math/gammafunction.d
index c9677c7..7f72234 100644
--- a/libphobos/src/std/internal/math/gammafunction.d
+++ b/libphobos/src/std/internal/math/gammafunction.d
@@ -21,6 +21,7 @@ Macros:
module std.internal.math.gammafunction;
import std.internal.math.errorfunction;
import std.math;
+import core.math : fabs, sin, sqrt;
pure:
nothrow:
@@ -34,46 +35,46 @@ immutable real EULERGAMMA = 0.57721_56649_01532_86060_65120_90082_40243_10421_59
// Polynomial approximations for gamma and loggamma.
-immutable real[8] GammaNumeratorCoeffs = [ 1.0,
- 0x1.acf42d903366539ep-1, 0x1.73a991c8475f1aeap-2, 0x1.c7e918751d6b2a92p-4,
- 0x1.86d162cca32cfe86p-6, 0x1.0c378e2e6eaf7cd8p-8, 0x1.dc5c66b7d05feb54p-12,
- 0x1.616457b47e448694p-15
+immutable real[8] GammaNumeratorCoeffs = [ 1.0L,
+ 0x1.acf42d903366539ep-1L, 0x1.73a991c8475f1aeap-2L, 0x1.c7e918751d6b2a92p-4L,
+ 0x1.86d162cca32cfe86p-6L, 0x1.0c378e2e6eaf7cd8p-8L, 0x1.dc5c66b7d05feb54p-12L,
+ 0x1.616457b47e448694p-15L
];
-immutable real[9] GammaDenominatorCoeffs = [ 1.0,
- 0x1.a8f9faae5d8fc8bp-2, -0x1.cb7895a6756eebdep-3, -0x1.7b9bab006d30652ap-5,
- 0x1.c671af78f312082ep-6, -0x1.a11ebbfaf96252dcp-11, -0x1.447b4d2230a77ddap-10,
- 0x1.ec1d45bb85e06696p-13,-0x1.d4ce24d05bd0a8e6p-17
+immutable real[9] GammaDenominatorCoeffs = [ 1.0L,
+ 0x1.a8f9faae5d8fc8bp-2L, -0x1.cb7895a6756eebdep-3L, -0x1.7b9bab006d30652ap-5L,
+ 0x1.c671af78f312082ep-6L, -0x1.a11ebbfaf96252dcp-11L, -0x1.447b4d2230a77ddap-10L,
+ 0x1.ec1d45bb85e06696p-13L,-0x1.d4ce24d05bd0a8e6p-17L
];
-immutable real[9] GammaSmallCoeffs = [ 1.0,
- 0x1.2788cfc6fb618f52p-1, -0x1.4fcf4026afa2f7ecp-1, -0x1.5815e8fa24d7e306p-5,
- 0x1.5512320aea2ad71ap-3, -0x1.59af0fb9d82e216p-5, -0x1.3b4b61d3bfdf244ap-7,
- 0x1.d9358e9d9d69fd34p-8, -0x1.38fc4bcbada775d6p-10
+immutable real[9] GammaSmallCoeffs = [ 1.0L,
+ 0x1.2788cfc6fb618f52p-1L, -0x1.4fcf4026afa2f7ecp-1L, -0x1.5815e8fa24d7e306p-5L,
+ 0x1.5512320aea2ad71ap-3L, -0x1.59af0fb9d82e216p-5L, -0x1.3b4b61d3bfdf244ap-7L,
+ 0x1.d9358e9d9d69fd34p-8L, -0x1.38fc4bcbada775d6p-10L
];
-immutable real[9] GammaSmallNegCoeffs = [ -1.0,
- 0x1.2788cfc6fb618f54p-1, 0x1.4fcf4026afa2bc4cp-1, -0x1.5815e8fa2468fec8p-5,
- -0x1.5512320baedaf4b6p-3, -0x1.59af0fa283baf07ep-5, 0x1.3b4a70de31e05942p-7,
- 0x1.d9398be3bad13136p-8, 0x1.291b73ee05bcbba2p-10
+immutable real[9] GammaSmallNegCoeffs = [ -1.0L,
+ 0x1.2788cfc6fb618f54p-1L, 0x1.4fcf4026afa2bc4cp-1L, -0x1.5815e8fa2468fec8p-5L,
+ -0x1.5512320baedaf4b6p-3L, -0x1.59af0fa283baf07ep-5L, 0x1.3b4a70de31e05942p-7L,
+ 0x1.d9398be3bad13136p-8L, 0x1.291b73ee05bcbba2p-10L
];
immutable real[7] logGammaStirlingCoeffs = [
- 0x1.5555555555553f98p-4, -0x1.6c16c16c07509b1p-9, 0x1.a01a012461cbf1e4p-11,
- -0x1.3813089d3f9d164p-11, 0x1.b911a92555a277b8p-11, -0x1.ed0a7b4206087b22p-10,
- 0x1.402523859811b308p-8
+ 0x1.5555555555553f98p-4L, -0x1.6c16c16c07509b1p-9L, 0x1.a01a012461cbf1e4p-11L,
+ -0x1.3813089d3f9d164p-11L, 0x1.b911a92555a277b8p-11L, -0x1.ed0a7b4206087b22p-10L,
+ 0x1.402523859811b308p-8L
];
immutable real[7] logGammaNumerator = [
- -0x1.0edd25913aaa40a2p+23, -0x1.31c6ce2e58842d1ep+24, -0x1.f015814039477c3p+23,
- -0x1.74ffe40c4b184b34p+22, -0x1.0d9c6d08f9eab55p+20, -0x1.54c6b71935f1fc88p+16,
- -0x1.0e761b42932b2aaep+11
+ -0x1.0edd25913aaa40a2p+23L, -0x1.31c6ce2e58842d1ep+24L, -0x1.f015814039477c3p+23L,
+ -0x1.74ffe40c4b184b34p+22L, -0x1.0d9c6d08f9eab55p+20L, -0x1.54c6b71935f1fc88p+16L,
+ -0x1.0e761b42932b2aaep+11L
];
immutable real[8] logGammaDenominator = [
- -0x1.4055572d75d08c56p+24, -0x1.deeb6013998e4d76p+24, -0x1.106f7cded5dcc79ep+24,
- -0x1.25e17184848c66d2p+22, -0x1.301303b99a614a0ap+19, -0x1.09e76ab41ae965p+15,
- -0x1.00f95ced9e5f54eep+9, 1.0
+ -0x1.4055572d75d08c56p+24L, -0x1.deeb6013998e4d76p+24L, -0x1.106f7cded5dcc79ep+24L,
+ -0x1.25e17184848c66d2p+22L, -0x1.301303b99a614a0ap+19L, -0x1.09e76ab41ae965p+15L,
+ -0x1.00f95ced9e5f54eep+9L, 1.0L
];
/*
@@ -89,9 +90,9 @@ real gammaStirling(real x)
// CEPHES code Copyright 1994 by Stephen L. Moshier
static immutable real[9] SmallStirlingCoeffs = [
- 0x1.55555555555543aap-4, 0x1.c71c71c720dd8792p-9, -0x1.5f7268f0b5907438p-9,
- -0x1.e13cd410e0477de6p-13, 0x1.9b0f31643442616ep-11, 0x1.2527623a3472ae08p-14,
- -0x1.37f6bc8ef8b374dep-11,-0x1.8c968886052b872ap-16, 0x1.76baa9c6d3eeddbcp-11
+ 0x1.55555555555543aap-4L, 0x1.c71c71c720dd8792p-9L, -0x1.5f7268f0b5907438p-9L,
+ -0x1.e13cd410e0477de6p-13L, 0x1.9b0f31643442616ep-11L, 0x1.2527623a3472ae08p-14L,
+ -0x1.37f6bc8ef8b374dep-11L,-0x1.8c968886052b872ap-16L, 0x1.76baa9c6d3eeddbcp-11L
];
static immutable real[7] LargeStirlingCoeffs = [ 1.0L,
@@ -144,76 +145,76 @@ real gammaStirling(real x)
real igammaTemmeLarge(real a, real x)
{
static immutable real[][13] coef = [
- [ -0.333333333333333333333, 0.0833333333333333333333,
- -0.0148148148148148148148, 0.00115740740740740740741,
- 0.000352733686067019400353, -0.0001787551440329218107,
- 0.39192631785224377817e-4, -0.218544851067999216147e-5,
- -0.18540622107151599607e-5, 0.829671134095308600502e-6,
- -0.176659527368260793044e-6, 0.670785354340149858037e-8,
- 0.102618097842403080426e-7, -0.438203601845335318655e-8,
- 0.914769958223679023418e-9, -0.255141939949462497669e-10,
- -0.583077213255042506746e-10, 0.243619480206674162437e-10,
- -0.502766928011417558909e-11 ],
- [ -0.00185185185185185185185, -0.00347222222222222222222,
- 0.00264550264550264550265, -0.000990226337448559670782,
- 0.000205761316872427983539, -0.40187757201646090535e-6,
- -0.18098550334489977837e-4, 0.764916091608111008464e-5,
- -0.161209008945634460038e-5, 0.464712780280743434226e-8,
- 0.137863344691572095931e-6, -0.575254560351770496402e-7,
- 0.119516285997781473243e-7, -0.175432417197476476238e-10,
- -0.100915437106004126275e-8, 0.416279299184258263623e-9,
- -0.856390702649298063807e-10 ],
- [ 0.00413359788359788359788, -0.00268132716049382716049,
- 0.000771604938271604938272, 0.200938786008230452675e-5,
- -0.000107366532263651605215, 0.529234488291201254164e-4,
- -0.127606351886187277134e-4, 0.342357873409613807419e-7,
- 0.137219573090629332056e-5, -0.629899213838005502291e-6,
- 0.142806142060642417916e-6, -0.204770984219908660149e-9,
- -0.140925299108675210533e-7, 0.622897408492202203356e-8,
- -0.136704883966171134993e-8 ],
- [ 0.000649434156378600823045, 0.000229472093621399176955,
- -0.000469189494395255712128, 0.000267720632062838852962,
- -0.756180167188397641073e-4, -0.239650511386729665193e-6,
- 0.110826541153473023615e-4, -0.56749528269915965675e-5,
- 0.142309007324358839146e-5, -0.278610802915281422406e-10,
- -0.169584040919302772899e-6, 0.809946490538808236335e-7,
- -0.191111684859736540607e-7 ],
- [ -0.000861888290916711698605, 0.000784039221720066627474,
- -0.000299072480303190179733, -0.146384525788434181781e-5,
- 0.664149821546512218666e-4, -0.396836504717943466443e-4,
- 0.113757269706784190981e-4, 0.250749722623753280165e-9,
- -0.169541495365583060147e-5, 0.890750753220530968883e-6,
- -0.229293483400080487057e-6],
- [ -0.000336798553366358150309, -0.697281375836585777429e-4,
- 0.000277275324495939207873, -0.000199325705161888477003,
- 0.679778047793720783882e-4, 0.141906292064396701483e-6,
- -0.135940481897686932785e-4, 0.801847025633420153972e-5,
- -0.229148117650809517038e-5 ],
- [ 0.000531307936463992223166, -0.000592166437353693882865,
- 0.000270878209671804482771, 0.790235323266032787212e-6,
- -0.815396936756196875093e-4, 0.561168275310624965004e-4,
- -0.183291165828433755673e-4, -0.307961345060330478256e-8,
- 0.346515536880360908674e-5, -0.20291327396058603727e-5,
- 0.57887928631490037089e-6 ],
- [ 0.000344367606892377671254, 0.517179090826059219337e-4,
- -0.000334931610811422363117, 0.000281269515476323702274,
- -0.000109765822446847310235, -0.127410090954844853795e-6,
- 0.277444515115636441571e-4, -0.182634888057113326614e-4,
- 0.578769494973505239894e-5 ],
- [ -0.000652623918595309418922, 0.000839498720672087279993,
- -0.000438297098541721005061, -0.696909145842055197137e-6,
- 0.000166448466420675478374, -0.000127835176797692185853,
- 0.462995326369130429061e-4 ],
- [ -0.000596761290192746250124, -0.720489541602001055909e-4,
- 0.000678230883766732836162, -0.0006401475260262758451,
- 0.000277501076343287044992 ],
- [ 0.00133244544948006563713, -0.0019144384985654775265,
- 0.00110893691345966373396 ],
- [ 0.00157972766073083495909, 0.000162516262783915816899,
- -0.00206334210355432762645, 0.00213896861856890981541,
- -0.00101085593912630031708 ],
- [ -0.00407251211951401664727, 0.00640336283380806979482,
- -0.00404101610816766177474 ]
+ [ -0.333333333333333333333L, 0.0833333333333333333333L,
+ -0.0148148148148148148148L, 0.00115740740740740740741L,
+ 0.000352733686067019400353L, -0.0001787551440329218107L,
+ 0.39192631785224377817e-4L, -0.218544851067999216147e-5L,
+ -0.18540622107151599607e-5L, 0.829671134095308600502e-6L,
+ -0.176659527368260793044e-6L, 0.670785354340149858037e-8L,
+ 0.102618097842403080426e-7L, -0.438203601845335318655e-8L,
+ 0.914769958223679023418e-9L, -0.255141939949462497669e-10L,
+ -0.583077213255042506746e-10L, 0.243619480206674162437e-10L,
+ -0.502766928011417558909e-11L ],
+ [ -0.00185185185185185185185L, -0.00347222222222222222222L,
+ 0.00264550264550264550265L, -0.000990226337448559670782L,
+ 0.000205761316872427983539L, -0.40187757201646090535e-6L,
+ -0.18098550334489977837e-4L, 0.764916091608111008464e-5L,
+ -0.161209008945634460038e-5L, 0.464712780280743434226e-8L,
+ 0.137863344691572095931e-6L, -0.575254560351770496402e-7L,
+ 0.119516285997781473243e-7L, -0.175432417197476476238e-10L,
+ -0.100915437106004126275e-8L, 0.416279299184258263623e-9L,
+ -0.856390702649298063807e-10L ],
+ [ 0.00413359788359788359788L, -0.00268132716049382716049L,
+ 0.000771604938271604938272L, 0.200938786008230452675e-5L,
+ -0.000107366532263651605215L, 0.529234488291201254164e-4L,
+ -0.127606351886187277134e-4L, 0.342357873409613807419e-7L,
+ 0.137219573090629332056e-5L, -0.629899213838005502291e-6L,
+ 0.142806142060642417916e-6L, -0.204770984219908660149e-9L,
+ -0.140925299108675210533e-7L, 0.622897408492202203356e-8L,
+ -0.136704883966171134993e-8L ],
+ [ 0.000649434156378600823045L, 0.000229472093621399176955L,
+ -0.000469189494395255712128L, 0.000267720632062838852962L,
+ -0.756180167188397641073e-4L, -0.239650511386729665193e-6L,
+ 0.110826541153473023615e-4L, -0.56749528269915965675e-5L,
+ 0.142309007324358839146e-5L, -0.278610802915281422406e-10L,
+ -0.169584040919302772899e-6L, 0.809946490538808236335e-7L,
+ -0.191111684859736540607e-7L ],
+ [ -0.000861888290916711698605L, 0.000784039221720066627474L,
+ -0.000299072480303190179733L, -0.146384525788434181781e-5L,
+ 0.664149821546512218666e-4L, -0.396836504717943466443e-4L,
+ 0.113757269706784190981e-4L, 0.250749722623753280165e-9L,
+ -0.169541495365583060147e-5L, 0.890750753220530968883e-6L,
+ -0.229293483400080487057e-6L ],
+ [ -0.000336798553366358150309L, -0.697281375836585777429e-4L,
+ 0.000277275324495939207873L, -0.000199325705161888477003L,
+ 0.679778047793720783882e-4L, 0.141906292064396701483e-6L,
+ -0.135940481897686932785e-4L, 0.801847025633420153972e-5L,
+ -0.229148117650809517038e-5L ],
+ [ 0.000531307936463992223166L, -0.000592166437353693882865L,
+ 0.000270878209671804482771L, 0.790235323266032787212e-6L,
+ -0.815396936756196875093e-4L, 0.561168275310624965004e-4L,
+ -0.183291165828433755673e-4L, -0.307961345060330478256e-8L,
+ 0.346515536880360908674e-5L, -0.20291327396058603727e-5L,
+ 0.57887928631490037089e-6L ],
+ [ 0.000344367606892377671254L, 0.517179090826059219337e-4L,
+ -0.000334931610811422363117L, 0.000281269515476323702274L,
+ -0.000109765822446847310235L, -0.127410090954844853795e-6L,
+ 0.277444515115636441571e-4L, -0.182634888057113326614e-4L,
+ 0.578769494973505239894e-5L ],
+ [ -0.000652623918595309418922L, 0.000839498720672087279993L,
+ -0.000438297098541721005061L, -0.696909145842055197137e-6L,
+ 0.000166448466420675478374L, -0.000127835176797692185853L,
+ 0.462995326369130429061e-4L ],
+ [ -0.000596761290192746250124L, -0.720489541602001055909e-4L,
+ 0.000678230883766732836162L, -0.0006401475260262758451L,
+ 0.000277501076343287044992L ],
+ [ 0.00133244544948006563713L, -0.0019144384985654775265L,
+ 0.00110893691345966373396L ],
+ [ 0.00157972766073083495909L, 0.000162516262783915816899L,
+ -0.00206334210355432762645L, 0.00213896861856890981541L,
+ -0.00101085593912630031708L ],
+ [ -0.00407251211951401664727L, 0.00640336283380806979482L,
+ -0.00404101610816766177474L ]
];
// avoid nans when one of the arguments is inf:
@@ -492,7 +493,7 @@ real logGamma(real x)
}
while ( x < 2.0L )
{
- if ( fabs(x) <= 0.03125 )
+ if ( fabs(x) <= 0.03125L )
{
if ( x == 0.0L )
return real.infinity;
@@ -568,9 +569,9 @@ real logGamma(real x)
assert( feqrel(log(fabs(gamma(testpoints[i]))), testpoints[i+1]) > real.mant_dig-5);
}
}
- assert(logGamma(-50.2) == log(fabs(gamma(-50.2))));
- assert(logGamma(-0.008) == log(fabs(gamma(-0.008))));
- assert(feqrel(logGamma(-38.8),log(fabs(gamma(-38.8)))) > real.mant_dig-4);
+ assert(feqrel(logGamma(-50.2L),log(fabs(gamma(-50.2L)))) > real.mant_dig-2);
+ assert(feqrel(logGamma(-0.008L),log(fabs(gamma(-0.008L)))) > real.mant_dig-2);
+ assert(feqrel(logGamma(-38.8L),log(fabs(gamma(-38.8L)))) > real.mant_dig-4);
static if (real.mant_dig >= 64) // incl. 80-bit reals
assert(feqrel(logGamma(1500.0L),log(gamma(1500.0L))) > real.mant_dig-2);
else static if (real.mant_dig >= 53) // incl. 64-bit reals
@@ -597,8 +598,8 @@ private {
*/
static if (floatTraits!(real).realFormat == RealFormat.ieeeQuadruple)
{
- enum real MAXLOG = 0x1.62e42fefa39ef35793c7673007e6p+13; // log(real.max)
- enum real MINLOG = -0x1.6546282207802c89d24d65e96274p+13; // log(real.min_normal*real.epsilon) = log(smallest denormal)
+ enum real MAXLOG = 0x1.62e42fefa39ef35793c7673007e6p+13L; // log(real.max)
+ enum real MINLOG = -0x1.6546282207802c89d24d65e96274p+13L; // log(real.min_normal*real.epsilon) = log(smallest denormal)
}
else static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended)
{
@@ -1039,17 +1040,17 @@ done:
// Test against Mathematica betaRegularized[z,a,b]
// These arbitrary points are chosen to give good code coverage.
- assert(feqrel(betaIncomplete(8, 10, 0.2), 0.010_934_315_234_099_2L) >= real.mant_dig - 5);
- assert(feqrel(betaIncomplete(2, 2.5, 0.9), 0.989_722_597_604_452_767_171_003_59L) >= real.mant_dig - 1);
+ assert(feqrel(betaIncomplete(8, 10, 0.2L), 0.010_934_315_234_099_2L) >= real.mant_dig - 5);
+ assert(feqrel(betaIncomplete(2, 2.5L, 0.9L), 0.989_722_597_604_452_767_171_003_59L) >= real.mant_dig - 1);
static if (real.mant_dig >= 64) // incl. 80-bit reals
- assert(feqrel(betaIncomplete(1000, 800, 0.5), 1.179140859734704555102808541457164E-06L) >= real.mant_dig - 13);
+ assert(feqrel(betaIncomplete(1000, 800, 0.5L), 1.179140859734704555102808541457164E-06L) >= real.mant_dig - 13);
else
- assert(feqrel(betaIncomplete(1000, 800, 0.5), 1.179140859734704555102808541457164E-06L) >= real.mant_dig - 14);
- assert(feqrel(betaIncomplete(0.0001, 10000, 0.0001), 0.999978059362107134278786L) >= real.mant_dig - 18);
- assert(betaIncomplete(0.01, 327726.7, 0.545113) == 1.0);
+ assert(feqrel(betaIncomplete(1000, 800, 0.5L), 1.179140859734704555102808541457164E-06L) >= real.mant_dig - 14);
+ assert(feqrel(betaIncomplete(0.0001, 10000, 0.0001L), 0.999978059362107134278786L) >= real.mant_dig - 18);
+ assert(betaIncomplete(0.01L, 327726.7L, 0.545113L) == 1.0);
assert(feqrel(betaIncompleteInv(8, 10, 0.010_934_315_234_099_2L), 0.2L) >= real.mant_dig - 2);
- assert(feqrel(betaIncomplete(0.01, 498.437, 0.0121433), 0.99999664562033077636065L) >= real.mant_dig - 1);
- assert(feqrel(betaIncompleteInv(5, 10, 0.2000002972865658842), 0.229121208190918L) >= real.mant_dig - 3);
+ assert(feqrel(betaIncomplete(0.01L, 498.437L, 0.0121433L), 0.99999664562033077636065L) >= real.mant_dig - 1);
+ assert(feqrel(betaIncompleteInv(5, 10, 0.2000002972865658842L), 0.229121208190918L) >= real.mant_dig - 3);
assert(feqrel(betaIncompleteInv(4, 7, 0.8000002209179505L), 0.483657360076904L) >= real.mant_dig - 3);
// Coverage tests. I don't have correct values for these tests, but
@@ -1060,32 +1061,32 @@ done:
// significant improvement over the original CEPHES code.
static if (real.mant_dig == 64) // 80-bit reals
{
- assert(betaIncompleteInv(0.01, 8e-48, 5.45464e-20) == 1-real.epsilon);
- assert(betaIncompleteInv(0.01, 8e-48, 9e-26) == 1-real.epsilon);
+ assert(betaIncompleteInv(0.01L, 8e-48L, 5.45464e-20L) == 1-real.epsilon);
+ assert(betaIncompleteInv(0.01L, 8e-48L, 9e-26L) == 1-real.epsilon);
// Beware: a one-bit change in pow() changes almost all digits in the result!
assert(feqrel(
- betaIncompleteInv(0x1.b3d151fbba0eb18p+1, 1.2265e-19, 2.44859e-18),
+ betaIncompleteInv(0x1.b3d151fbba0eb18p+1L, 1.2265e-19L, 2.44859e-18L),
0x1.c0110c8531d0952cp-1L
) > 10);
// This next case uncovered a one-bit difference in the FYL2X instruction
// between Intel and AMD processors. This difference gets magnified by 2^^38.
// WolframAlpha crashes attempting to calculate this.
- assert(feqrel(betaIncompleteInv(0x1.ff1275ae5b939bcap-41, 4.6713e18, 0.0813601),
+ assert(feqrel(betaIncompleteInv(0x1.ff1275ae5b939bcap-41L, 4.6713e18L, 0.0813601L),
0x1.f97749d90c7adba8p-63L) >= real.mant_dig - 39);
- real a1 = 3.40483;
- assert(betaIncompleteInv(a1, 4.0640301659679627772e19L, 0.545113) == 0x1.ba8c08108aaf5d14p-109);
- real b1 = 2.82847e-25;
- assert(feqrel(betaIncompleteInv(0.01, b1, 9e-26), 0x1.549696104490aa9p-830L) >= real.mant_dig-10);
+ real a1 = 3.40483L;
+ assert(betaIncompleteInv(a1, 4.0640301659679627772e19L, 0.545113L) == 0x1.ba8c08108aaf5d14p-109L);
+ real b1 = 2.82847e-25L;
+ assert(feqrel(betaIncompleteInv(0.01L, b1, 9e-26L), 0x1.549696104490aa9p-830L) >= real.mant_dig-10);
// --- Problematic cases ---
// This is a situation where the series expansion fails to converge
- assert( isNaN(betaIncompleteInv(0.12167, 4.0640301659679627772e19L, 0.0813601)));
+ assert( isNaN(betaIncompleteInv(0.12167L, 4.0640301659679627772e19L, 0.0813601L)));
// This next result is almost certainly erroneous.
// Mathematica states: "(cannot be determined by current methods)"
- assert(betaIncomplete(1.16251e20, 2.18e39, 5.45e-20) == -real.infinity);
+ assert(betaIncomplete(1.16251e20L, 2.18e39L, 5.45e-20L) == -real.infinity);
// WolframAlpha gives no result for this, though indicates that it approximately 1.0 - 1.3e-9
- assert(1 - betaIncomplete(0.01, 328222, 4.0375e-5) == 0x1.5f62926b4p-30);
+ assert(1 - betaIncomplete(0.01L, 328222, 4.0375e-5L) == 0x1.5f62926b4p-30L);
}
}
@@ -1326,11 +1327,13 @@ real betaDistPowerSeries(real a, real b, real x )
* values of a and x.
*/
real gammaIncomplete(real a, real x )
-in {
+in
+{
assert(x >= 0);
assert(a > 0);
}
-body {
+do
+{
/* left tail of incomplete gamma function:
*
* inf. k
@@ -1370,11 +1373,13 @@ body {
/** ditto */
real gammaIncompleteCompl(real a, real x )
-in {
+in
+{
assert(x >= 0);
assert(a > 0);
}
-body {
+do
+{
if (x == 0)
return 1.0L;
if ( (x < 1.0L) || (x < a) )
@@ -1456,11 +1461,13 @@ body {
* root of incompleteGammaCompl(a,x) - p = 0.
*/
real gammaIncompleteComplInv(real a, real p)
-in {
+in
+{
assert(p >= 0 && p <= 1);
assert(a>0);
}
-body {
+do
+{
if (p == 0) return real.infinity;
real y0 = p;
@@ -1585,17 +1592,17 @@ ihalve:
@safe unittest
{
//Values from Excel's GammaInv(1-p, x, 1)
-assert(fabs(gammaIncompleteComplInv(1, 0.5) - 0.693147188044814) < 0.00000005);
-assert(fabs(gammaIncompleteComplInv(12, 0.99) - 5.42818075054289) < 0.00000005);
-assert(fabs(gammaIncompleteComplInv(100, 0.8) - 91.5013985848288L) < 0.000005);
+assert(fabs(gammaIncompleteComplInv(1, 0.5L) - 0.693147188044814L) < 0.00000005L);
+assert(fabs(gammaIncompleteComplInv(12, 0.99L) - 5.42818075054289L) < 0.00000005L);
+assert(fabs(gammaIncompleteComplInv(100, 0.8L) - 91.5013985848288L) < 0.000005L);
assert(gammaIncomplete(1, 0)==0);
assert(gammaIncompleteCompl(1, 0)==1);
assert(gammaIncomplete(4545, real.infinity)==1);
// Values from Excel's (1-GammaDist(x, alpha, 1, TRUE))
-assert(fabs(1.0L-gammaIncompleteCompl(0.5, 2) - 0.954499729507309L) < 0.00000005);
-assert(fabs(gammaIncomplete(0.5, 2) - 0.954499729507309L) < 0.00000005);
+assert(fabs(1.0L-gammaIncompleteCompl(0.5L, 2) - 0.954499729507309L) < 0.00000005L);
+assert(fabs(gammaIncomplete(0.5L, 2) - 0.954499729507309L) < 0.00000005L);
// Fixed Cephes bug:
assert(gammaIncompleteCompl(384, real.infinity)==0);
assert(gammaIncompleteComplInv(3, 0)==real.infinity);
@@ -1603,9 +1610,9 @@ assert(gammaIncompleteComplInv(3, 0)==real.infinity);
// x was larger than a, but not by much, and both were large:
// The value is from WolframAlpha (Gamma[100000, 100001, inf] / Gamma[100000])
static if (real.mant_dig >= 64) // incl. 80-bit reals
- assert(fabs(gammaIncompleteCompl(100000, 100001) - 0.49831792109) < 0.000000000005);
+ assert(fabs(gammaIncompleteCompl(100000, 100001) - 0.49831792109L) < 0.000000000005L);
else
- assert(fabs(gammaIncompleteCompl(100000, 100001) - 0.49831792109) < 0.00000005);
+ assert(fabs(gammaIncompleteCompl(100000, 100001) - 0.49831792109L) < 0.00000005L);
}
@@ -1688,7 +1695,7 @@ real digamma(real x)
s += 1.0;
}
- if ( s < 1.0e17 )
+ if ( s < 1.0e17L )
{
z = 1.0/(s * s);
y = z * poly(z, Bn_n);
@@ -1755,7 +1762,7 @@ real logmdigamma(real x)
}
real y;
- if ( s < 1.0e17 )
+ if ( s < 1.0e17L )
{
immutable real z = 1.0/(s * s);
y = z * poly(z, Bn_n);
@@ -1771,9 +1778,9 @@ real logmdigamma(real x)
assert(isIdentical(logmdigamma(NaN(0xABC)), NaN(0xABC)));
assert(logmdigamma(0.0) == real.infinity);
for (auto x = 0.01; x < 1.0; x += 0.1)
- assert(approxEqual(digamma(x), log(x) - logmdigamma(x)));
+ assert(isClose(digamma(x), log(x) - logmdigamma(x)));
for (auto x = 1.0; x < 15.0; x += 1.0)
- assert(approxEqual(digamma(x), log(x) - logmdigamma(x)));
+ assert(isClose(digamma(x), log(x) - logmdigamma(x)));
}
/** Inverse of the Log Minus Digamma function
@@ -1830,12 +1837,12 @@ real logmdigammaInverse(real y)
tuple(1017.644138623741168814449776695062817947092468536L, 1.0L/1024),
];
foreach (test; testData)
- assert(approxEqual(logmdigammaInverse(test[0]), test[1], 2e-15, 0));
-
- assert(approxEqual(logmdigamma(logmdigammaInverse(1)), 1, 1e-15, 0));
- assert(approxEqual(logmdigamma(logmdigammaInverse(real.min_normal)), real.min_normal, 1e-15, 0));
- assert(approxEqual(logmdigamma(logmdigammaInverse(real.max/2)), real.max/2, 1e-15, 0));
- assert(approxEqual(logmdigammaInverse(logmdigamma(1)), 1, 1e-15, 0));
- assert(approxEqual(logmdigammaInverse(logmdigamma(real.min_normal)), real.min_normal, 1e-15, 0));
- assert(approxEqual(logmdigammaInverse(logmdigamma(real.max/2)), real.max/2, 1e-15, 0));
+ assert(isClose(logmdigammaInverse(test[0]), test[1], 2e-15L));
+
+ assert(isClose(logmdigamma(logmdigammaInverse(1)), 1, 1e-15L));
+ assert(isClose(logmdigamma(logmdigammaInverse(real.min_normal)), real.min_normal, 1e-15L));
+ assert(isClose(logmdigamma(logmdigammaInverse(real.max/2)), real.max/2, 1e-15L));
+ assert(isClose(logmdigammaInverse(logmdigamma(1)), 1, 1e-15L));
+ assert(isClose(logmdigammaInverse(logmdigamma(real.min_normal)), real.min_normal, 1e-15L));
+ assert(isClose(logmdigammaInverse(logmdigamma(real.max/2)), real.max/2, 1e-15L));
}
diff --git a/libphobos/src/std/internal/memory.d b/libphobos/src/std/internal/memory.d
new file mode 100644
index 0000000..991cd68
--- /dev/null
+++ b/libphobos/src/std/internal/memory.d
@@ -0,0 +1,58 @@
+module std.internal.memory;
+
+package(std):
+
+version (D_Exceptions)
+{
+ import core.exception : onOutOfMemoryError;
+ private enum allocationFailed = `onOutOfMemoryError();`;
+}
+else
+{
+ private enum allocationFailed = `assert(0, "Memory allocation failed");`;
+}
+
+// (below comments are non-DDOC, but are written in similar style)
+
+/+
+Mnemonic for `enforce!OutOfMemoryError(malloc(size))` that (unlike malloc)
+can be considered pure because it causes the program to abort if the result
+of the allocation is null, with the consequence that errno will not be
+visibly changed by calling this function. Note that `malloc` can also
+return `null` in non-failure situations if given an argument of 0. Hence,
+it is a programmer error to use this function if the requested allocation
+size is logically permitted to be zero. `enforceCalloc` and `enforceRealloc`
+work analogously.
+
+All these functions are usable in `betterC`.
++/
+void* enforceMalloc()(size_t size) @nogc nothrow pure @safe
+{
+ auto result = fakePureMalloc(size);
+ if (!result) mixin(allocationFailed);
+ return result;
+}
+
+// ditto
+void* enforceCalloc()(size_t nmemb, size_t size) @nogc nothrow pure @safe
+{
+ auto result = fakePureCalloc(nmemb, size);
+ if (!result) mixin(allocationFailed);
+ return result;
+}
+
+// ditto
+void* enforceRealloc()(return scope void* ptr, size_t size) @nogc nothrow pure @system
+{
+ auto result = fakePureRealloc(ptr, size);
+ if (!result) mixin(allocationFailed);
+ return result;
+}
+
+// Purified for local use only.
+extern (C) @nogc nothrow pure private
+{
+ pragma(mangle, "malloc") void* fakePureMalloc(size_t) @safe;
+ pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size) @safe;
+ pragma(mangle, "realloc") void* fakePureRealloc(return scope void* ptr, size_t size) @system;
+}
diff --git a/libphobos/src/std/internal/scopebuffer.d b/libphobos/src/std/internal/scopebuffer.d
index 70a7c8d..7c1f8c0 100644
--- a/libphobos/src/std/internal/scopebuffer.d
+++ b/libphobos/src/std/internal/scopebuffer.d
@@ -2,7 +2,7 @@
* Copyright: 2014 by Digital Mars
* License: $(LINK2 http://boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: Walter Bright
- * Source: $(PHOBOSSRC std/internal/_scopebuffer.d)
+ * Source: $(PHOBOSSRC std/internal/scopebuffer.d)
*/
module std.internal.scopebuffer;
@@ -12,6 +12,7 @@ module std.internal.scopebuffer;
import core.stdc.stdlib : realloc;
import std.traits;
+import std.internal.attributes : betterC;
/**************************************
* ScopeBuffer encapsulates using a local array as a temporary buffer.
@@ -74,11 +75,11 @@ string cat(string s1, string s2)
return textbuf[].idup;
}
---
- * ScopeBuffer is intended for high performance usages in $(D @system) and $(D @trusted) code.
+ * ScopeBuffer is intended for high performance usages in `@system` and `@trusted` code.
* It is designed to fit into two 64 bit registers, again for high performance use.
* If used incorrectly, memory leaks and corruption can result. Be sure to use
* $(D scope(exit) textbuf.free();) for proper cleanup, and do not refer to a ScopeBuffer
- * instance's contents after $(D ScopeBuffer.free()) has been called.
+ * instance's contents after `ScopeBuffer.free()` has been called.
*
* The `realloc` parameter defaults to C's `realloc()`. Another can be supplied to override it.
*
@@ -122,13 +123,13 @@ if (isAssignable!T &&
assert(!(buf.length & wasResized)); // assure even length of scratch buffer space
assert(buf.length <= uint.max); // because we cast to uint later
}
- body
+ do
{
this.buf = buf.ptr;
this.bufLen = cast(uint) buf.length;
}
- @system unittest
+ @system @betterC unittest
{
ubyte[10] tmpbuf = void;
auto sbuf = ScopeBuffer!ubyte(tmpbuf);
@@ -171,8 +172,8 @@ if (isAssignable!T &&
/************************
* Append array s to the buffer.
*
- * If $(D const(T)) can be converted to $(D T), then put will accept
- * $(D const(T)[]) as input. It will accept a $(D T[]) otherwise.
+ * If `const(T)` can be converted to `T`, then put will accept
+ * `const(T)[]` as input. It will accept a `T[]` otherwise.
*/
package alias CT = Select!(is(const(T) : T), const(T), T);
/// ditto
@@ -203,7 +204,7 @@ if (isAssignable!T &&
assert(upper <= bufLen);
assert(lower <= upper);
}
- body
+ do
{
return buf[lower .. upper];
}
@@ -244,7 +245,7 @@ if (isAssignable!T &&
{
assert(i <= this.used);
}
- body
+ do
{
this.used = cast(uint) i;
}
@@ -263,7 +264,7 @@ if (isAssignable!T &&
{
assert(newsize <= uint.max);
}
- body
+ do
{
//writefln("%s: oldsize %s newsize %s", id, buf.length, newsize);
newsize |= wasResized;
@@ -289,7 +290,7 @@ if (isAssignable!T &&
}
}
-@system unittest
+@system @betterC unittest
{
import core.stdc.stdio;
import std.range;
@@ -350,7 +351,7 @@ if (isAssignable!T &&
}
// const
-@system unittest
+@system @betterC unittest
{
char[10] tmpbuf = void;
auto textbuf = ScopeBuffer!char(tmpbuf);
@@ -377,14 +378,14 @@ auto scopeBuffer(T)(T[] tmpbuf)
}
///
-@system unittest
+@system @betterC unittest
{
ubyte[10] tmpbuf = void;
auto sb = scopeBuffer(tmpbuf);
scope(exit) sb.free();
}
-@system unittest
+@system @betterC unittest
{
ScopeBuffer!(int*) b;
int*[] s;
diff --git a/libphobos/src/std/internal/test/dummyrange.d b/libphobos/src/std/internal/test/dummyrange.d
index a6bce0a..e07e275 100644
--- a/libphobos/src/std/internal/test/dummyrange.d
+++ b/libphobos/src/std/internal/test/dummyrange.d
@@ -340,7 +340,7 @@ if (is(T == uint))
pure struct Cmp(T)
if (is(T == double))
{
- import std.math : approxEqual;
+ import std.math.operations : isClose;
static auto iota(size_t low = 1, size_t high = 11)
{
@@ -354,7 +354,7 @@ if (is(T == double))
arr = iota().array;
}
- alias cmp = approxEqual!(double,double);
+ alias cmp = isClose!(double,double,double);
enum dummyValue = 1337.0;
enum dummyValueRslt = 1337.0 * 2.0;
@@ -386,8 +386,6 @@ struct TestFoo
pure struct Cmp(T)
if (is(T == TestFoo))
{
- import std.math : approxEqual;
-
static auto iota(size_t low = 1, size_t high = 11)
{
import std.algorithm.iteration : map;
@@ -421,7 +419,6 @@ if (is(T == TestFoo))
{
import std.algorithm.comparison : equal;
import std.range : iota, retro, repeat;
- import std.traits : Unqual;
static void testInputRange(T,Cmp)()
{
@@ -431,7 +428,7 @@ if (is(T == TestFoo))
{
if (numRuns == 1)
{
- static if (is(Unqual!(ElementType!(T)) == uint))
+ static if (is(immutable ElementType!(T) == immutable uint))
{
it.reinit();
}
@@ -540,7 +537,7 @@ if (is(T == TestFoo))
import std.meta : AliasSeq;
- foreach (S; AliasSeq!(uint, double, TestFoo))
+ static foreach (S; AliasSeq!(uint, double, TestFoo))
{
foreach (T; AllDummyRangesType!(S[]))
{
diff --git a/libphobos/src/std/internal/windows/advapi32.d b/libphobos/src/std/internal/windows/advapi32.d
index 9ed6762..2220eec 100644
--- a/libphobos/src/std/internal/windows/advapi32.d
+++ b/libphobos/src/std/internal/windows/advapi32.d
@@ -6,13 +6,13 @@
*
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: Kenji Hara
- * Source: $(PHOBOSSRC std/internal/windows/_advapi32.d)
+ * Source: $(PHOBOSSRC std/internal/windows/advapi32.d)
*/
module std.internal.windows.advapi32;
version (Windows):
-import core.sys.windows.windows;
+import core.sys.windows.winbase, core.sys.windows.winnt, core.sys.windows.winreg;
pragma(lib, "advapi32.lib");