diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2019-06-18 20:42:10 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-11-30 16:53:28 +0100 |
commit | 5fee5ec362f7a243f459e6378fd49dfc89dc9fb5 (patch) | |
tree | 61d1bdbca854a903c0860406f457f06b2040be7a /libphobos/src/std/internal | |
parent | b3f60112edcb85b459e60f66c44a55138b1cef49 (diff) | |
download | gcc-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.d | 11 | ||||
-rw-r--r-- | libphobos/src/std/internal/cstring.d | 318 | ||||
-rw-r--r-- | libphobos/src/std/internal/math/biguintcore.d | 822 | ||||
-rw-r--r-- | libphobos/src/std/internal/math/biguintnoasm.d | 18 | ||||
-rw-r--r-- | libphobos/src/std/internal/math/errorfunction.d | 139 | ||||
-rw-r--r-- | libphobos/src/std/internal/math/gammafunction.d | 303 | ||||
-rw-r--r-- | libphobos/src/std/internal/memory.d | 58 | ||||
-rw-r--r-- | libphobos/src/std/internal/scopebuffer.d | 29 | ||||
-rw-r--r-- | libphobos/src/std/internal/test/dummyrange.d | 11 | ||||
-rw-r--r-- | libphobos/src/std/internal/windows/advapi32.d | 4 |
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"); |