aboutsummaryrefslogtreecommitdiff
path: root/libphobos/src/std/functional.d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2019-06-18 20:42:10 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2021-11-30 16:53:28 +0100
commit5fee5ec362f7a243f459e6378fd49dfc89dc9fb5 (patch)
tree61d1bdbca854a903c0860406f457f06b2040be7a /libphobos/src/std/functional.d
parentb3f60112edcb85b459e60f66c44a55138b1cef49 (diff)
downloadgcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.zip
gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.tar.gz
gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.tar.bz2
d: Import dmd b8384668f, druntime e6caaab9, phobos 5ab9ad256 (v2.098.0-beta.1)
The D front-end is now itself written in D, in order to build GDC, you will need a working GDC compiler (GCC version 9.1 or later). GCC changes: - Add support for bootstrapping the D front-end. These add the required components in order to have a D front-end written in D itself. Because the compiler front-end only depends on the core runtime modules, only libdruntime is built for the bootstrap stages. D front-end changes: - Import dmd v2.098.0-beta.1. Druntime changes: - Import druntime v2.098.0-beta.1. Phobos changes: - Import phobos v2.098.0-beta.1. The jump from v2.076.1 to v2.098.0 covers nearly 4 years worth of development on the D programming language and run-time libraries. ChangeLog: * Makefile.def: Add bootstrap to libbacktrace, libphobos, zlib, and libatomic. * Makefile.in: Regenerate. * Makefile.tpl (POSTSTAGE1_HOST_EXPORTS): Fix command for GDC. (STAGE1_CONFIGURE_FLAGS): Add --with-libphobos-druntime-only if target-libphobos-bootstrap. (STAGE2_CONFIGURE_FLAGS): Likewise. * configure: Regenerate. * configure.ac: Add support for bootstrapping D front-end. config/ChangeLog: * acx.m4 (ACX_PROG_GDC): New m4 function. gcc/ChangeLog: * Makefile.in (GDC): New variable. (GDCFLAGS): New variable. * configure: Regenerate. * configure.ac: Add call to ACX_PROG_GDC. Substitute GDCFLAGS. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd b8384668f. * Make-lang.in (d-warn): Use strict warnings. (DMD_WARN_CXXFLAGS): Remove. (DMD_COMPILE): Remove. (CHECKING_DFLAGS): Define. (WARN_DFLAGS): Define. (ALL_DFLAGS): Define. (DCOMPILE.base): Define. (DCOMPILE): Define. (DPOSTCOMPILE): Define. (DLINKER): Define. (DLLINKER): Define. (D_FRONTEND_OBJS): Add new dmd front-end objects. (D_GENERATED_SRCS): Remove. (D_GENERATED_OBJS): Remove. (D_ALL_OBJS): Remove D_GENERATED_OBJS. (d21$(exeext)): Build using DLLINKER and -static-libphobos. (d.tags): Remove dmd/*.c and dmd/root/*.c. (d.mostlyclean): Remove D_GENERATED_SRCS, d/idgen$(build_exeext), d/impcnvgen$(build_exeext). (D_INCLUDES): Include $(srcdir)/d/dmd/res. (CFLAGS-d/id.o): Remove. (CFLAGS-d/impcnvtab.o): Remove. (d/%.o): Build using DCOMPILE and DPOSTCOMPILE. Update dependencies from d/dmd/%.c to d/dmd/%.d. (d/idgen$(build_exeext)): Remove. (d/impcnvgen$(build_exeext)): Remove. (d/id.c): Remove. (d/id.h): Remove. (d/impcnvtab.c): Remove. (d/%.dmdgen.o): Remove. (D_SYSTEM_H): Remove. (d/idgen.dmdgen.o): Remove. (d/impcnvgen.dmdgen.o): Remove. * config-lang.in (boot_language): New variable. * d-attribs.cc: Include dmd/expression.h. * d-builtins.cc: Include d-frontend.h. (build_frontend_type): Update for new front-end interface. (d_eval_constant_expression): Likewise. (d_build_builtins_module): Likewise. (maybe_set_builtin_1): Likewise. (d_build_d_type_nodes): Likewise. * d-codegen.cc (d_decl_context): Likewise. (declaration_reference_p): Likewise. (declaration_type): Likewise. (parameter_reference_p): Likewise. (parameter_type): Likewise. (get_array_length): Likewise. (build_delegate_cst): Likewise. (build_typeof_null_value): Likewise. (identity_compare_p): Likewise. (lower_struct_comparison): Likewise. (build_filename_from_loc): Likewise. (build_assert_call): Remove LIBCALL_SWITCH_ERROR. (build_bounds_index_condition): Call LIBCALL_ARRAYBOUNDS_INDEXP on bounds error. (build_bounds_slice_condition): Call LIBCALL_ARRAYBOUNDS_SLICEP on bounds error. (array_bounds_check): Update for new front-end interface. (checkaction_trap_p): Handle CHECKACTION_context. (get_function_type): Update for new front-end interface. (d_build_call): Likewise. * d-compiler.cc: Remove include of dmd/scope.h. (Compiler::genCmain): Remove. (Compiler::paintAsType): Update for new front-end interface. (Compiler::onParseModule): Likewise. * d-convert.cc (convert_expr): Remove call to LIBCALL_ARRAYCAST. (convert_for_rvalue): Update for new front-end interface. (convert_for_assignment): Likewise. (convert_for_condition): Likewise. (d_array_convert): Likewise. * d-diagnostic.cc (error): Remove. (errorSupplemental): Remove. (warning): Remove. (warningSupplemental): Remove. (deprecation): Remove. (deprecationSupplemental): Remove. (message): Remove. (vtip): New. * d-frontend.cc (global): Remove. (Global::_init): Remove. (Global::startGagging): Remove. (Global::endGagging): Remove. (Global::increaseErrorCount): Remove. (Loc::Loc): Remove. (Loc::toChars): Remove. (Loc::equals): Remove. (isBuiltin): Update for new front-end interface. (eval_builtin): Likewise. (getTypeInfoType): Likewise. (inlineCopy): Remove. * d-incpath.cc: Include d-frontend.h. (add_globalpaths): Call d_gc_malloc to allocate Strings. (add_filepaths): Likewise. * d-lang.cc: Include dmd/id.h, dmd/root/file.h, d-frontend.h. Remove include of dmd/mars.h, id.h. (entrypoint_module): Remove. (entrypoint_root_module): Remove. (deps_write_string): Update for new front-end interface. (deps_write): Likewise. (d_init_options): Call rt_init. Remove setting global params that are default initialized by the front-end. (d_handle_option): Handle OPT_fcheckaction_, OPT_fdump_c___spec_, OPT_fdump_c___spec_verbose, OPT_fextern_std_, OPT_fpreview, OPT_revert, OPT_fsave_mixins_, and OPT_ftransition. (d_post_options): Propagate dip1021 and dip1000 preview flags to dip25, and flag_diagnostics_show_caret to printErrorContext. (d_add_entrypoint_module): Remove. (d_parse_file): Update for new front-end interface. (d_type_promotes_to): Likewise. (d_types_compatible_p): Likewise. * d-longdouble.cc (CTFloat::zero): Remove. (CTFloat::one): Remove. (CTFloat::minusone): Remove. (CTFloat::half): Remove. * d-system.h (POSIX): Remove. (realpath): Remove. (isalpha): Remove. (isalnum): Remove. (isdigit): Remove. (islower): Remove. (isprint): Remove. (isspace): Remove. (isupper): Remove. (isxdigit): Remove. (tolower): Remove. (_mkdir): Remove. (INT32_MAX): Remove. (INT32_MIN): Remove. (INT64_MIN): Remove. (UINT32_MAX): Remove. (UINT64_MAX): Remove. * d-target.cc: Include calls.h. (target): Remove. (define_float_constants): Remove initialization of snan. (Target::_init): Update for new front-end interface. (Target::isVectorTypeSupported): Likewise. (Target::isVectorOpSupported): Remove cases for unordered operators. (TargetCPP::typeMangle): Update for new front-end interface. (TargetCPP::parameterType): Likewise. (Target::systemLinkage): Likewise. (Target::isReturnOnStack): Likewise. (Target::isCalleeDestroyingArgs): Define. (Target::preferPassByRef): Define. * d-tree.h (d_add_entrypoint_module): Remove. * decl.cc (gcc_attribute_p): Update for new front-end interface. (apply_pragma_crt): Define. (DeclVisitor::visit(PragmaDeclaration *)): Handle pragmas crt_constructor and crt_destructor. (DeclVisitor::visit(TemplateDeclaration *)): Update for new front-end interface. (DeclVisitor::visit): Likewise. (DeclVisitor::finish_vtable): Likewise. (get_symbol_decl): Error if template has more than one nesting context. Update for new front-end interface. (make_thunk): Update for new front-end interface. (get_vtable_decl): Likewise. * expr.cc (ExprVisitor::visit): Likewise. (build_return_dtor): Likewise. * imports.cc (ImportVisitor::visit): Likewise. * intrinsics.cc: Include dmd/expression.h. Remove include of dmd/mangle.h. (maybe_set_intrinsic): Update for new front-end interface. * intrinsics.def (INTRINSIC_ROL): Update intrinsic signature. (INTRINSIC_ROR): Likewise. (INTRINSIC_ROR_TIARG): Likewise. (INTRINSIC_TOPREC): Likewise. (INTRINSIC_TOPRECL): Likewise. (INTRINSIC_TAN): Update intrinsic module and signature. (INTRINSIC_ISNAN): Likewise. (INTRINSIC_ISFINITE): Likewise. (INTRINSIC_COPYSIGN): Define intrinsic. (INTRINSIC_COPYSIGNI): Define intrinsic. (INTRINSIC_EXP): Update intrinsic module. (INTRINSIC_EXPM1): Likewise. (INTRINSIC_EXP2): Likewise. (INTRINSIC_LOG): Likewise. (INTRINSIC_LOG2): Likewise. (INTRINSIC_LOG10): Likewise. (INTRINSIC_POW): Likewise. (INTRINSIC_ROUND): Likewise. (INTRINSIC_FLOORF): Likewise. (INTRINSIC_FLOOR): Likewise. (INTRINSIC_FLOORL): Likewise. (INTRINSIC_CEILF): Likewise. (INTRINSIC_CEIL): Likewise. (INTRINSIC_CEILL): Likewise. (INTRINSIC_TRUNC): Likewise. (INTRINSIC_FMIN): Likewise. (INTRINSIC_FMAX): Likewise. (INTRINSIC_FMA): Likewise. (INTRINSIC_VA_ARG): Update intrinsic signature. (INTRINSIC_VASTART): Likewise. * lang.opt (fcheck=): Add alternate aliases for contract switches. (fcheckaction=): New option. (check_action): New Enum and EnumValue entries. (fdump-c++-spec-verbose): New option. (fdump-c++-spec=): New option. (fextern-std=): New option. (extern_stdcpp): New Enum and EnumValue entries (fpreview=): New options. (frevert=): New options. (fsave-mixins): New option. (ftransition=): Update options. * modules.cc (get_internal_fn): Replace Prot with Visibility. (build_internal_fn): Likewise. (build_dso_cdtor_fn): Likewise. (build_module_tree): Remove check for __entrypoint module. * runtime.def (P5): Define. (ARRAYBOUNDS_SLICEP): Define. (ARRAYBOUNDS_INDEXP): Define. (NEWTHROW): Define. (ADCMP2): Remove. (ARRAYCAST): Remove. (SWITCH_STRING): Remove. (SWITCH_USTRING): Remove. (SWITCH_DSTRING): Remove. (SWITCH_ERROR): Remove. * toir.cc (IRVisitor::visit): Update for new front-end interface. (IRVisitor::check_previous_goto): Remove checks for case and default statements. (IRVisitor::visit(SwitchStatement *)): Remove handling of string switch conditions. * typeinfo.cc: Include d-frontend.h. (get_typeinfo_kind): Update for new front-end interface. (make_frontend_typeinfo): Likewise. (TypeInfoVisitor::visit): Likewise. (builtin_typeinfo_p): Likewise. (get_typeinfo_decl): Likewise. (build_typeinfo): Likewise. * types.cc (valist_array_p): Likewise. (make_array_type): Likewise. (merge_aggregate_types): Likewise. (TypeVisitor::visit(TypeBasic *)): Likewise. (TypeVisitor::visit(TypeFunction *)): Likewise. (TypeVisitor::visit(TypeStruct *)): Update comment. * verstr.h: Removed. * d-frontend.h: New file. gcc/po/ChangeLog: * EXCLUDES: Remove d/dmd sources from list. gcc/testsuite/ChangeLog: * gdc.dg/Wcastresult2.d: Update test. * gdc.dg/asm1.d: Likewise. * gdc.dg/asm2.d: Likewise. * gdc.dg/asm3.d: Likewise. * gdc.dg/gdc282.d: Likewise. * gdc.dg/imports/gdc170.d: Likewise. * gdc.dg/intrinsics.d: Likewise. * gdc.dg/pr101672.d: Likewise. * gdc.dg/pr90650a.d: Likewise. * gdc.dg/pr90650b.d: Likewise. * gdc.dg/pr94777a.d: Likewise. * gdc.dg/pr95250.d: Likewise. * gdc.dg/pr96869.d: Likewise. * gdc.dg/pr98277.d: Likewise. * gdc.dg/pr98457.d: Likewise. * gdc.dg/simd1.d: Likewise. * gdc.dg/simd2a.d: Likewise. * gdc.dg/simd2b.d: Likewise. * gdc.dg/simd2c.d: Likewise. * gdc.dg/simd2d.d: Likewise. * gdc.dg/simd2e.d: Likewise. * gdc.dg/simd2f.d: Likewise. * gdc.dg/simd2g.d: Likewise. * gdc.dg/simd2h.d: Likewise. * gdc.dg/simd2i.d: Likewise. * gdc.dg/simd2j.d: Likewise. * gdc.dg/simd7951.d: Likewise. * gdc.dg/torture/gdc309.d: Likewise. * gdc.dg/torture/pr94424.d: Likewise. * gdc.dg/torture/pr94777b.d: Likewise. * lib/gdc-utils.exp (gdc-convert-args): Handle new compiler options. (gdc-convert-test): Handle CXXFLAGS, EXTRA_OBJC_SOURCES, and ARG_SETS test directives. (gdc-do-test): Only import modules in the test run directory. * gdc.dg/pr94777c.d: New test. * gdc.dg/pr96156b.d: New test. * gdc.dg/pr96157c.d: New test. * gdc.dg/simd_ctfe.d: New test. * gdc.dg/torture/simd17344.d: New test. * gdc.dg/torture/simd20052.d: New test. * gdc.dg/torture/simd6.d: New test. * gdc.dg/torture/simd7.d: New test. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e6caaab9. * libdruntime/Makefile.am (D_EXTRA_FLAGS): Build libdruntime with -fpreview=dip1000, -fpreview=fieldwise, and -fpreview=dtorfields. (ALL_DRUNTIME_SOURCES): Add DRUNTIME_DSOURCES_STDCXX. (DRUNTIME_DSOURCES): Update list of C binding modules. (DRUNTIME_DSOURCES_STDCXX): Likewise. (DRUNTIME_DSOURCES_LINUX): Likewise. (DRUNTIME_DSOURCES_OPENBSD): Likewise. (DRUNTIME_DISOURCES): Remove __entrypoint.di. * libdruntime/Makefile.in: Regenerated. * libdruntime/__entrypoint.di: Removed. * libdruntime/gcc/deh.d (_d_isbaseof): Update signature. (_d_createTrace): Likewise. (__gdc_begin_catch): Remove reference to the exception. (_d_throw): Increment reference count of thrown object before unwind. (__gdc_personality): Chain exceptions with Throwable.chainTogether. * libdruntime/gcc/emutls.d: Update imports. * libdruntime/gcc/sections/elf.d: Update imports. (DSO.moduleGroup): Update signature. * libdruntime/gcc/sections/macho.d: Update imports. (DSO.moduleGroup): Update signature. * libdruntime/gcc/sections/pecoff.d: Update imports. (DSO.moduleGroup): Update signature. * src/MERGE: Merge upstream phobos 5ab9ad256. * src/Makefile.am (D_EXTRA_DFLAGS): Add -fpreview=dip1000 and -fpreview=dtorfields flags. (PHOBOS_DSOURCES): Update list of std modules. * src/Makefile.in: Regenerate. * testsuite/lib/libphobos.exp (libphobos-dg-test): Handle assembly compile types. (dg-test): Override. (additional_prunes): Define. (libphobos-dg-prune): Filter any additional_prunes set by tests. * testsuite/libphobos.aa/test_aa.d: Update test. * testsuite/libphobos.druntime/druntime.exp (version_flags): Add -fversion=CoreUnittest. * testsuite/libphobos.druntime_shared/druntime_shared.exp (version_flags): Add -fversion=CoreUnittest -fversion=Shared. * testsuite/libphobos.exceptions/unknown_gc.d: Update test. * testsuite/libphobos.hash/test_hash.d: Update test. * testsuite/libphobos.phobos/phobos.exp (version_flags): Add -fversion=StdUnittest * testsuite/libphobos.phobos_shared/phobos_shared.exp (version_flags): Likewise. * testsuite/libphobos.shared/host.c: Update test. * testsuite/libphobos.shared/load.d: Update test. * testsuite/libphobos.shared/load_13414.d: Update test. * testsuite/libphobos.thread/fiber_guard_page.d: Update test. * testsuite/libphobos.thread/tlsgc_sections.d: Update test. * testsuite/testsuite_flags.in: Add -fpreview=dip1000 to --gdcflags. * testsuite/libphobos.shared/link_mod_collision.d: Removed. * testsuite/libphobos.shared/load_mod_collision.d: Removed. * testsuite/libphobos.betterc/betterc.exp: New test. * testsuite/libphobos.config/config.exp: New test. * testsuite/libphobos.gc/gc.exp: New test. * testsuite/libphobos.imports/imports.exp: New test. * testsuite/libphobos.lifetime/lifetime.exp: New test. * testsuite/libphobos.unittest/unittest.exp: New test.
Diffstat (limited to 'libphobos/src/std/functional.d')
-rw-r--r--libphobos/src/std/functional.d688
1 files changed, 470 insertions, 218 deletions
diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d
index f35d6ff..cec61fe 100644
--- a/libphobos/src/std/functional.d
+++ b/libphobos/src/std/functional.d
@@ -8,6 +8,7 @@ functions are helpful when constructing predicates for the algorithms in
$(MREF std, algorithm) or $(MREF std, range).
$(SCRIPT inhibitQuickIndex = 1;)
+$(DIVC quickindex,
$(BOOKTABLE ,
$(TR $(TH Function Name) $(TH Description)
)
@@ -20,9 +21,6 @@ $(TR $(TH Function Name) $(TH Description)
functions one after the other, using one function's result for the next
function's argument.
))
- $(TR $(TD $(LREF forward))
- $(TD Forwards function arguments while saving ref-ness.
- ))
$(TR $(TD $(LREF lessThan), $(LREF greaterThan), $(LREF equalTo))
$(TD Ready-made predicate functions to compare two values.
))
@@ -36,7 +34,11 @@ $(TR $(TH Function Name) $(TH Description)
$(TD Creates a function that binds the first argument of a given function
to a given value.
))
- $(TR $(TD $(LREF reverseArgs), $(LREF binaryReverseArgs))
+ $(TR $(TD $(LREF curry))
+ $(TD Converts a multi-argument function into a series of single-argument
+ functions. f(x, y) == curry(f)(x)(y)
+ ))
+ $(TR $(TD $(LREF reverseArgs))
$(TD Predicate that reverses the order of its arguments.
))
$(TR $(TD $(LREF toDelegate))
@@ -46,12 +48,12 @@ $(TR $(TH Function Name) $(TH Description)
$(TD Create a unary or binary function from a string. Most often
used when defining algorithms on ranges.
))
-)
+))
Copyright: Copyright Andrei Alexandrescu 2008 - 2009.
License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: $(HTTP erdani.org, Andrei Alexandrescu)
-Source: $(PHOBOSSRC std/_functional.d)
+Source: $(PHOBOSSRC std/functional.d)
*/
/*
Copyright Andrei Alexandrescu 2008 - 2009.
@@ -61,9 +63,10 @@ Distributed under the Boost Software License, Version 1.0.
*/
module std.functional;
-import std.meta; // AliasSeq, Reverse
-import std.traits; // isCallable, Parameters
+import std.meta : AliasSeq, Reverse;
+import std.traits : isCallable, Parameters;
+import std.internal.attributes : betterC;
private template needOpCallAlias(alias fun)
{
@@ -93,12 +96,19 @@ private template needOpCallAlias(alias fun)
}
/**
-Transforms a string representing an expression into a unary
-function. The string must either use symbol name $(D a) as
-the parameter or provide the symbol via the $(D parmName) argument.
-If $(D fun) is not a string, $(D unaryFun) aliases itself away to $(D fun).
+Transforms a `string` representing an expression into a unary
+function. The `string` must either use symbol name `a` as
+the parameter or provide the symbol via the `parmName` argument.
+
+Params:
+ fun = a `string` or a callable
+ parmName = the name of the parameter if `fun` is a string. Defaults
+ to `"a"`.
+Returns:
+ If `fun` is a `string`, a new single parameter function
+
+ If `fun` is not a `string`, an alias to `fun`.
*/
-
template unaryFun(alias fun, string parmName = "a")
{
static if (is(typeof(fun) : string))
@@ -116,7 +126,7 @@ template unaryFun(alias fun, string parmName = "a")
}
else static if (needOpCallAlias!fun)
{
- // Issue 9906
+ // https://issues.dlang.org/show_bug.cgi?id=9906
alias unaryFun = fun.opCall;
}
else
@@ -147,7 +157,7 @@ template unaryFun(alias fun, string parmName = "a")
int num = 41;
assert(unaryFun!"a + 1"(num) == 42);
- // Issue 9906
+ // https://issues.dlang.org/show_bug.cgi?id=9906
struct Seen
{
static bool opCall(int n) { return true; }
@@ -176,13 +186,20 @@ template unaryFun(alias fun, string parmName = "a")
}
/**
-Transforms a string representing an expression into a binary function. The
-string must either use symbol names $(D a) and $(D b) as the parameters or
-provide the symbols via the $(D parm1Name) and $(D parm2Name) arguments.
-If $(D fun) is not a string, $(D binaryFun) aliases itself away to
-$(D fun).
+Transforms a `string` representing an expression into a binary function. The
+`string` must either use symbol names `a` and `b` as the parameters or
+provide the symbols via the `parm1Name` and `parm2Name` arguments.
+
+Params:
+ fun = a `string` or a callable
+ parm1Name = the name of the first parameter if `fun` is a string.
+ Defaults to `"a"`.
+ parm2Name = the name of the second parameter if `fun` is a string.
+ Defaults to `"b"`.
+Returns:
+ If `fun` is not a string, `binaryFun` aliases itself away to
+ `fun`.
*/
-
template binaryFun(alias fun, string parm1Name = "a",
string parm2Name = "b")
{
@@ -203,7 +220,7 @@ template binaryFun(alias fun, string parm1Name = "a",
}
else static if (needOpCallAlias!fun)
{
- // Issue 9906
+ // https://issues.dlang.org/show_bug.cgi?id=9906
alias binaryFun = fun.opCall;
}
else
@@ -233,7 +250,7 @@ template binaryFun(alias fun, string parm1Name = "a",
//@@BUG
//assert(binaryFun!("return a + b;")(41, 1) == 42);
- // Issue 9906
+ // https://issues.dlang.org/show_bug.cgi?id=9906
struct Seen
{
static bool opCall(int x, int y) { return true; }
@@ -301,7 +318,7 @@ private uint _ctfeSkipName(ref string op, string name)
return 0;
}
-// returns 1 if $(D fun) is trivial unary function
+// returns 1 if `fun` is trivial unary function
private uint _ctfeMatchUnary(string fun, string name)
{
if (!__ctfe) assert(false);
@@ -348,7 +365,7 @@ private uint _ctfeMatchUnary(string fun, string name)
static assert(_ctfeMatchUnary("ё[21]", "ё"));
}
-// returns 1 if $(D fun) is trivial binary function
+// returns 1 if `fun` is trivial binary function
private uint _ctfeMatchBinary(string fun, string name1, string name2)
{
if (!__ctfe) assert(false);
@@ -531,13 +548,18 @@ alias equalTo = safeOp!"==";
assert(!equalTo(-1, ~0U));
}
/**
- N-ary predicate that reverses the order of arguments, e.g., given
- $(D pred(a, b, c)), returns $(D pred(c, b, a)).
+N-ary predicate that reverses the order of arguments, e.g., given
+$(D pred(a, b, c)), returns $(D pred(c, b, a)).
+
+Params:
+ pred = A callable
+Returns:
+ A function which calls `pred` after reversing the given parameters
*/
template reverseArgs(alias pred)
{
auto reverseArgs(Args...)(auto ref Args args)
- if (is(typeof(pred(Reverse!args))))
+ if (is(typeof(pred(Reverse!args))))
{
return pred(Reverse!args);
}
@@ -548,6 +570,24 @@ template reverseArgs(alias pred)
{
alias gt = reverseArgs!(binaryFun!("a < b"));
assert(gt(2, 1) && !gt(1, 1));
+}
+
+///
+@safe unittest
+{
+ int x = 42;
+ bool xyz(int a, int b) { return a * x < b / x; }
+ auto foo = &xyz;
+ foo(4, 5);
+ alias zyx = reverseArgs!(foo);
+ assert(zyx(5, 4) == foo(4, 5));
+}
+
+///
+@safe unittest
+{
+ alias gt = reverseArgs!(binaryFun!("a < b"));
+ assert(gt(2, 1) && !gt(1, 1));
int x = 42;
bool xyz(int a, int b) { return a * x < b / x; }
auto foo = &xyz;
@@ -581,38 +621,13 @@ template reverseArgs(alias pred)
}
/**
- Binary predicate that reverses the order of arguments, e.g., given
- $(D pred(a, b)), returns $(D pred(b, a)).
-*/
-template binaryReverseArgs(alias pred)
-{
- auto binaryReverseArgs(ElementType1, ElementType2)
- (auto ref ElementType1 a, auto ref ElementType2 b)
- {
- return pred(b, a);
- }
-}
-
-///
-@safe unittest
-{
- alias gt = binaryReverseArgs!(binaryFun!("a < b"));
- assert(gt(2, 1) && !gt(1, 1));
-}
-
-///
-@safe unittest
-{
- int x = 42;
- bool xyz(int a, int b) { return a * x < b / x; }
- auto foo = &xyz;
- foo(4, 5);
- alias zyx = binaryReverseArgs!(foo);
- assert(zyx(5, 4) == foo(4, 5));
-}
+Negates predicate `pred`.
-/**
-Negates predicate $(D pred).
+Params:
+ pred = A string or a callable
+Returns:
+ A function which calls `pred` and returns the logical negation of its
+ return value.
*/
template not(alias pred)
{
@@ -633,7 +648,6 @@ template not(alias pred)
@safe unittest
{
import std.algorithm.searching : find;
- import std.functional;
import std.uni : isWhite;
string a = " Hello, world!";
assert(find!(not!isWhite)(a) == "Hello, world!");
@@ -653,18 +667,20 @@ template not(alias pred)
/**
$(LINK2 http://en.wikipedia.org/wiki/Partial_application, Partially
applies) $(D_PARAM fun) by tying its first argument to $(D_PARAM arg).
+
+Params:
+ fun = A callable
+ arg = The first argument to apply to `fun`
+Returns:
+ A new function which calls `fun` with `arg` plus the passed parameters.
*/
template partial(alias fun, alias arg)
{
- static if (is(typeof(fun) == delegate) || is(typeof(fun) == function))
- {
- import std.traits : ReturnType;
- ReturnType!fun partial(Parameters!fun[1..$] args2)
- {
- return fun(arg, args2);
- }
- }
- else
+ import std.traits : isCallable;
+ // Check whether fun is a user defined type which implements opCall or a template.
+ // As opCall itself can be templated, std.traits.isCallable does not work here.
+ enum isSomeFunctor = (is(typeof(fun) == struct) || is(typeof(fun) == class)) && __traits(hasMember, fun, "opCall");
+ static if (isSomeFunctor || __traits(isTemplate, fun))
{
auto partial(Ts...)(Ts args2)
{
@@ -687,6 +703,36 @@ template partial(alias fun, alias arg)
}
}
}
+ else static if (!isCallable!fun)
+ {
+ static assert(false, "Cannot apply partial to a non-callable '" ~ fun.stringof ~ "'.");
+ }
+ else // Assume fun is callable and uniquely defined.
+ {
+ static if (Parameters!fun.length == 0)
+ {
+ static assert(0, "Cannot partially apply '" ~ fun.stringof ~ "'." ~
+ "'" ~ fun.stringof ~ "' has 0 arguments.");
+ }
+ else static if (!is(typeof(arg) : Parameters!fun[0]))
+ {
+ string errorMsg()
+ {
+ string msg = "Argument mismatch for '" ~ fun.stringof ~ "': expected " ~
+ Parameters!fun[0].stringof ~ ", but got " ~ typeof(arg).stringof ~ ".";
+ return msg;
+ }
+ static assert(0, errorMsg());
+ }
+ else
+ {
+ import std.traits : ReturnType;
+ ReturnType!fun partial(Parameters!fun[1..$] args2)
+ {
+ return fun(arg, args2);
+ }
+ }
+ }
}
///
@@ -773,6 +819,11 @@ template partial(alias fun, alias arg)
assert(partial!(tcallable, 5)(6) == 11);
static assert(!is(typeof(partial!(tcallable, "5")(6))));
+ static struct NonCallable{}
+ static assert(!__traits(compiles, partial!(NonCallable, 5)), "Partial should not work on non-callable structs.");
+ static assert(!__traits(compiles, partial!(NonCallable.init, 5)),
+ "Partial should not work on instances of non-callable structs.");
+
static A funOneArg(A)(A a) { return a; }
alias funOneArg1 = partial!(funOneArg, 1);
assert(funOneArg1() == 1);
@@ -786,15 +837,223 @@ template partial(alias fun, alias arg)
assert(dg2() == 1);
}
+// Fix https://issues.dlang.org/show_bug.cgi?id=15732
+@safe unittest
+{
+ // Test whether it works with functions.
+ auto partialFunction(){
+ auto fullFunction = (float a, float b, float c) => a + b / c;
+ alias apply1 = partial!(fullFunction, 1);
+ return &apply1;
+ }
+ auto result = partialFunction()(2, 4);
+ assert(result == 1.5f);
+
+ // And with delegates.
+ auto partialDelegate(float c){
+ auto fullDelegate = (float a, float b) => a + b / c;
+ alias apply1 = partial!(fullDelegate, 1);
+ return &apply1;
+ }
+ auto result2 = partialDelegate(4)(2);
+ assert(result2 == 1.5f);
+}
+
/**
-Takes multiple functions and adjoins them together. The result is a
-$(REF Tuple, std,typecons) with one element per passed-in function. Upon
-invocation, the returned tuple is the adjoined results of all
-functions.
+Takes a function of (potentially) many arguments, and returns a function taking
+one argument and returns a callable taking the rest. f(x, y) == curry(f)(x)(y)
+
+Params:
+ F = a function taking at least one argument
+ t = a callable object whose opCall takes at least 1 object
+Returns:
+ A single parameter callable object
+*/
+template curry(alias F)
+if (isCallable!F && Parameters!F.length)
+{
+ //inspired from the implementation from Artur Skawina here:
+ //https://forum.dlang.org/post/mailman.1626.1340110492.24740.digitalmars-d@puremagic.com
+ //This implementation stores a copy of all filled in arguments with each curried result
+ //this way, the curried functions are independent and don't share any references
+ //eg: auto fc = curry!f; auto fc1 = fc(1); auto fc2 = fc(2); fc1(3) != fc2(3)
+ struct CurryImpl(size_t N)
+ {
+ alias FParams = Parameters!F;
+ FParams[0 .. N] storedArguments;
+ static if (N > 0)
+ {
+ this(U : FParams[N - 1])(ref CurryImpl!(N - 1) prev, ref U arg)
+ {
+ storedArguments[0 .. N - 1] = prev.storedArguments[];
+ storedArguments[N-1] = arg;
+ }
+ }
+
+ auto opCall(U : FParams[N])(auto ref U arg) return scope
+ {
+ static if (N == FParams.length - 1)
+ {
+ return F(storedArguments, arg);
+ }
+ else
+ {
+ return CurryImpl!(N + 1)(this, arg);
+ }
+ }
+ }
+
+ auto curry()
+ {
+ CurryImpl!0 res;
+ return res; // return CurryImpl!0.init segfaults for delegates on Windows
+ }
+}
+
+///
+pure @safe @nogc nothrow unittest
+{
+ int f(int x, int y, int z)
+ {
+ return x + y + z;
+ }
+ auto cf = curry!f;
+ auto cf1 = cf(1);
+ auto cf2 = cf(2);
+
+ assert(cf1(2)(3) == f(1, 2, 3));
+ assert(cf2(2)(3) == f(2, 2, 3));
+}
+
+///ditto
+auto curry(T)(T t)
+if (isCallable!T && Parameters!T.length)
+{
+ static auto fun(ref T inst, ref Parameters!T args)
+ {
+ return inst(args);
+ }
+
+ return curry!fun()(t);
+}
+
+///
+pure @safe @nogc nothrow unittest
+{
+ //works with callable structs too
+ struct S
+ {
+ int w;
+ int opCall(int x, int y, int z)
+ {
+ return w + x + y + z;
+ }
+ }
+
+ S s;
+ s.w = 5;
+
+ auto cs = curry(s);
+ auto cs1 = cs(1);
+ auto cs2 = cs(2);
+
+ assert(cs1(2)(3) == s(1, 2, 3));
+ assert(cs1(2)(3) == (1 + 2 + 3 + 5));
+ assert(cs2(2)(3) ==s(2, 2, 3));
+}
+
+
+@safe pure @nogc nothrow unittest
+{
+ //currying a single argument function does nothing
+ int pork(int a){ return a*2;}
+ auto curryPork = curry!pork;
+ assert(curryPork(0) == pork(0));
+ assert(curryPork(1) == pork(1));
+ assert(curryPork(-1) == pork(-1));
+ assert(curryPork(1000) == pork(1000));
+
+ //test 2 argument function
+ double mixedVeggies(double a, int b, bool)
+ {
+ return a + b;
+ }
+
+ auto mixedCurry = curry!mixedVeggies;
+ assert(mixedCurry(10)(20)(false) == mixedVeggies(10, 20, false));
+ assert(mixedCurry(100)(200)(true) == mixedVeggies(100, 200, true));
+
+ // struct with opCall
+ struct S
+ {
+ double opCall(int x, double y, short z) const pure nothrow @nogc
+ {
+ return x*y*z;
+ }
+ }
+
+ S s;
+ auto curriedStruct = curry(s);
+ assert(curriedStruct(1)(2)(short(3)) == s(1, 2, short(3)));
+ assert(curriedStruct(300)(20)(short(10)) == s(300, 20, short(10)));
+}
+
+pure @safe nothrow unittest
+{
+ auto cfl = curry!((double a, int b) => a + b);
+ assert(cfl(13)(2) == 15);
+
+ int c = 42;
+ auto cdg = curry!((double a, int b) => a + b + c);
+ assert(cdg(13)(2) == 57);
+
+ static class C
+ {
+ int opCall(int mult, int add) pure @safe nothrow @nogc scope
+ {
+ return mult * 42 + add;
+ }
+ }
+
+ scope C ci = new C();
+ scope cc = curry(ci);
+ assert(cc(2)(4) == ci(2, 4));
+}
+
+// Disallows callables without parameters
+pure @safe @nogc nothrow unittest
+{
+ static void noargs() {}
+ static assert(!__traits(compiles, curry!noargs()));
+
+ static struct NoArgs
+ {
+ void opCall() {}
+ }
+
+ static assert(!__traits(compiles, curry(NoArgs.init)));
+}
+
+private template Iota(size_t n)
+{
+ static if (n == 0)
+ alias Iota = AliasSeq!();
+ else
+ alias Iota = AliasSeq!(Iota!(n - 1), n - 1);
+}
+
+/**
+Takes multiple functions and adjoins them together.
+
+Params:
+ F = the call-able(s) to adjoin
+Returns:
+ A new function which returns a $(REF Tuple, std,typecons). Each of the
+ elements of the tuple will be the return values of `F`.
Note: In the special case where only a single function is provided
($(D F.length == 1)), adjoin simply aliases to the single passed function
-($(D F[0])).
+(`F[0]`).
*/
template adjoin(F...)
if (F.length == 1)
@@ -808,27 +1067,21 @@ if (F.length > 1)
auto adjoin(V...)(auto ref V a)
{
import std.typecons : tuple;
- static if (F.length == 2)
- {
- return tuple(F[0](a), F[1](a));
- }
- else static if (F.length == 3)
- {
- return tuple(F[0](a), F[1](a), F[2](a));
- }
- else
+ import std.meta : staticMap;
+
+ auto resultElement(size_t i)()
{
- import std.format : format;
- import std.range : iota;
- return mixin (q{tuple(%(F[%s](a)%|, %))}.format(iota(0, F.length)));
+ return F[i](a);
}
+
+ return tuple(staticMap!(resultElement, Iota!(F.length)));
}
}
///
@safe unittest
{
- import std.functional, std.typecons : Tuple;
+ import std.typecons : Tuple;
static bool f1(int a) { return a != 0; }
static int f2(int a) { return a / 2; }
auto x = adjoin!(f1, f2)(5);
@@ -881,37 +1134,49 @@ if (F.length > 1)
enum Tuple!(IS, IS, IS, IS) ret2 = adjoin!(bar, bar, bar, bar)();
}
+// https://issues.dlang.org/show_bug.cgi?id=21347
+@safe @betterC unittest
+{
+ alias f = (int n) => n + 1;
+ alias g = (int n) => n + 2;
+ alias h = (int n) => n + 3;
+ alias i = (int n) => n + 4;
+
+ auto result = adjoin!(f, g, h, i)(0);
+
+ assert(result[0] == 1);
+ assert(result[1] == 2);
+ assert(result[2] == 3);
+ assert(result[3] == 4);
+}
+
/**
- Composes passed-in functions $(D fun[0], fun[1], ...) returning a
- function $(D f(x)) that in turn returns $(D
- fun[0](fun[1](...(x)))...). Each function can be a regular
- functions, a delegate, or a string.
+ Composes passed-in functions $(D fun[0], fun[1], ...).
+
+ Params:
+ fun = the call-able(s) or `string`(s) to compose into one function
+ Returns:
+ A new function `f(x)` that in turn returns `fun[0](fun[1](...(x)))...`.
See_Also: $(LREF pipe)
*/
template compose(fun...)
+if (fun.length > 0)
{
static if (fun.length == 1)
{
alias compose = unaryFun!(fun[0]);
}
- else static if (fun.length == 2)
+ else
{
- // starch
alias fun0 = unaryFun!(fun[0]);
- alias fun1 = unaryFun!(fun[1]);
+ alias rest = compose!(fun[1 .. $]);
- // protein: the core composition operation
- typeof({ E a; return fun0(fun1(a)); }()) compose(E)(E a)
+ auto compose(Args...)(Args args)
{
- return fun0(fun1(a));
+ return fun0(rest(args));
}
}
- else
- {
- // protein: assembling operations
- alias compose = compose!(fun[0], compose!(fun[1 .. $]));
- }
}
///
@@ -927,12 +1192,28 @@ template compose(fun...)
assert(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3]));
}
+// https://issues.dlang.org/show_bug.cgi?id=6484
+@safe unittest
+{
+ int f(int a) { return a; }
+ int g(int a) { return a; }
+ int h(int a,int b,int c) { return a * b * c; }
+
+ alias F = compose!(f,g,h);
+ assert(F(1,2,3) == f(g(h(1,2,3))));
+}
+
/**
Pipes functions in sequence. Offers the same functionality as $(D
compose), but with functions specified in reverse order. This may
lead to more readable code in some situation because the order of
execution is the same as lexical order.
+ Params:
+ fun = the call-able(s) or `string`(s) to compose into one function
+ Returns:
+ A new function `f(x)` that in turn returns `fun[$-1](...fun[1](fun[0](x)))...`.
+
Example:
----
@@ -946,6 +1227,7 @@ int[] a = pipe!(readText, split, map!(to!(int)))("file.txt");
*/
alias pipe(fun...) = compose!(Reverse!(fun));
+///
@safe unittest
{
import std.conv : to;
@@ -985,26 +1267,36 @@ unittest
}
----
-Technically the memoized function should be pure because $(D memoize) assumes it will
-always return the same result for a given tuple of arguments. However, $(D memoize) does not
-enforce that because sometimes it
-is useful to memoize an impure function, too.
+Params:
+ fun = the call-able to memozie
+ maxSize = The maximum size of the GC buffer to hold the return values
+Returns:
+ A new function which calls `fun` and caches its return values.
+
+Note:
+ Technically the memoized function should be pure because `memoize` assumes it will
+ always return the same result for a given tuple of arguments. However, `memoize` does not
+ enforce that because sometimes it is useful to memoize an impure function, too.
*/
template memoize(alias fun)
{
import std.traits : ReturnType;
- // alias Args = Parameters!fun; // Bugzilla 13580
+ // https://issues.dlang.org/show_bug.cgi?id=13580
+ // alias Args = Parameters!fun;
ReturnType!fun memoize(Parameters!fun args)
{
alias Args = Parameters!fun;
import std.typecons : Tuple;
+ import std.traits : Unqual;
- static ReturnType!fun[Tuple!Args] memo;
+ static Unqual!(ReturnType!fun)[Tuple!Args] memo;
auto t = Tuple!Args(args);
if (auto p = t in memo)
return *p;
- return memo[t] = fun(args);
+ auto r = fun(args);
+ memo[t] = r;
+ return r;
}
}
@@ -1012,12 +1304,14 @@ template memoize(alias fun)
template memoize(alias fun, uint maxSize)
{
import std.traits : ReturnType;
- // alias Args = Parameters!fun; // Bugzilla 13580
+ // https://issues.dlang.org/show_bug.cgi?id=13580
+ // alias Args = Parameters!fun;
ReturnType!fun memoize(Parameters!fun args)
{
- import std.traits : hasIndirections;
+ import std.meta : staticMap;
+ import std.traits : hasIndirections, Unqual;
import std.typecons : tuple;
- static struct Value { Parameters!fun args; ReturnType!fun res; }
+ static struct Value { staticMap!(Unqual, Parameters!fun) args; Unqual!(ReturnType!fun) res; }
static Value[] memo;
static size_t[] initialized;
@@ -1036,7 +1330,7 @@ template memoize(alias fun, uint maxSize)
}
import core.bitop : bt, bts;
- import std.conv : emplace;
+ import core.lifetime : emplace;
size_t hash;
foreach (ref arg; args)
@@ -1046,7 +1340,9 @@ template memoize(alias fun, uint maxSize)
if (!bt(initialized.ptr, idx1))
{
emplace(&memo[idx1], args, fun(args));
- bts(initialized.ptr, idx1); // only set to initialized after setting args and value (bugzilla 14025)
+ // only set to initialized after setting args and value
+ // https://issues.dlang.org/show_bug.cgi?id=14025
+ bts(initialized.ptr, idx1);
return memo[idx1].res;
}
else if (memo[idx1].args == args)
@@ -1056,7 +1352,7 @@ template memoize(alias fun, uint maxSize)
if (!bt(initialized.ptr, idx2))
{
emplace(&memo[idx2], memo[idx1]);
- bts(initialized.ptr, idx2); // only set to initialized after setting args and value (bugzilla 14025)
+ bts(initialized.ptr, idx2);
}
else if (memo[idx2].args == args)
return memo[idx2].res;
@@ -1072,9 +1368,10 @@ template memoize(alias fun, uint maxSize)
* To _memoize a recursive function, simply insert the memoized call in lieu of the plain recursive call.
* For example, to transform the exponential-time Fibonacci implementation into a linear-time computation:
*/
-@safe unittest
+@safe nothrow
+unittest
{
- ulong fib(ulong n) @safe
+ ulong fib(ulong n) @safe nothrow
{
return n < 2 ? n : memoize!fib(n - 2) + memoize!fib(n - 1);
}
@@ -1094,8 +1391,8 @@ template memoize(alias fun, uint maxSize)
}
/**
- * This memoizes all values of $(D fact) up to the largest argument. To only cache the final
- * result, move $(D memoize) outside the function as shown below.
+ * This memoizes all values of `fact` up to the largest argument. To only cache the final
+ * result, move `memoize` outside the function as shown below.
*/
@safe unittest
{
@@ -1108,7 +1405,7 @@ template memoize(alias fun, uint maxSize)
}
/**
- * When the $(D maxSize) parameter is specified, memoize will used
+ * When the `maxSize` parameter is specified, memoize will used
* a fixed size hash table to limit the number of cached entries.
*/
@system unittest // not @safe due to memoize
@@ -1154,7 +1451,7 @@ template memoize(alias fun, uint maxSize)
}
assert(fact(10) == 3628800);
- // Issue 12568
+ // https://issues.dlang.org/show_bug.cgi?id=12568
static uint len2(const string s) { // Error
alias mLen2 = memoize!len2;
if (s.length == 0)
@@ -1169,8 +1466,9 @@ template memoize(alias fun, uint maxSize)
assert(func(int.init) == 1);
}
-// 16079: memoize should work with arrays
-@safe unittest
+// https://issues.dlang.org/show_bug.cgi?id=16079
+// memoize should work with arrays
+@system unittest // not @safe with -dip1000 due to memoize
{
int executed = 0;
T median(T)(const T[] nums) {
@@ -1193,7 +1491,7 @@ template memoize(alias fun, uint maxSize)
assert(executed == 1);
}
-// 16079: memoize should work with structs
+// https://issues.dlang.org/show_bug.cgi?id=16079: memoize should work with structs
@safe unittest
{
int executed = 0;
@@ -1212,9 +1510,20 @@ template memoize(alias fun, uint maxSize)
assert(executed == 1);
}
-// 16079: memoize should work with classes
+// https://issues.dlang.org/show_bug.cgi?id=20439 memoize should work with void opAssign
@safe unittest
{
+ static struct S
+ {
+ void opAssign(S) {}
+ }
+
+ assert(memoize!(() => S()) == S());
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=16079: memoize should work with classes
+@system unittest // not @safe with -dip1000 due to memoize
+{
int executed = 0;
T pickFirst(T)(T first)
{
@@ -1246,6 +1555,33 @@ template memoize(alias fun, uint maxSize)
assert(executed == 1);
}
+// https://issues.dlang.org/show_bug.cgi?id=20302
+@system unittest
+{
+ version (none) // TODO change `none` to `all` and fix remaining limitations
+ struct S { const int len; }
+ else
+ struct S { int len; }
+
+ static string fun000( string str, S s) { return str[0 .. s.len] ~ "123"; }
+ static string fun001( string str, const S s) { return str[0 .. s.len] ~ "123"; }
+ static string fun010(const string str, S s) { return str[0 .. s.len] ~ "123"; }
+ static string fun011(const string str, const S s) { return str[0 .. s.len] ~ "123"; }
+ static const(string) fun100( string str, S s) { return str[0 .. s.len] ~ "123"; }
+ static const(string) fun101( string str, const S s) { return str[0 .. s.len] ~ "123"; }
+ static const(string) fun110(const string str, S s) { return str[0 .. s.len] ~ "123"; }
+ static const(string) fun111(const string str, const S s) { return str[0 .. s.len] ~ "123"; }
+
+ static foreach (fun; AliasSeq!(fun000, fun001, fun010, fun011, fun100, fun101, fun110, fun111))
+ {{
+ alias mfun = memoize!fun;
+ assert(mfun("abcdefgh", S(3)) == "abc123");
+
+ alias mfun2 = memoize!(fun, 42);
+ assert(mfun2("asd", S(3)) == "asd123");
+ }}
+}
+
private struct DelegateFaker(F)
{
import std.typecons : FuncInfo, MemberFunctionGenerator;
@@ -1305,6 +1641,11 @@ private struct DelegateFaker(F)
* Convert a callable to a delegate with the same parameter list and
* return type, avoiding heap allocations and use of auxiliary storage.
*
+ * Params:
+ * fp = a function pointer or an aggregate type with `opCall` defined.
+ * Returns:
+ * A delegate with the context pointer pointing to nothing.
+ *
* Example:
* ----
* void doStuff() {
@@ -1321,7 +1662,7 @@ private struct DelegateFaker(F)
*
* BUGS:
* $(UL
- * $(LI Does not work with $(D @safe) functions.)
+ * $(LI Does not work with `@safe` functions.)
* $(LI Ignores C-style / D-style variadic arguments.)
* )
*/
@@ -1467,98 +1808,9 @@ if (isCallable!(F))
}
}
-/**
-Forwards function arguments with saving ref-ness.
-*/
+// forward used to be here but was moved to druntime
template forward(args...)
{
- static if (args.length)
- {
- import std.algorithm.mutation : move;
-
- alias arg = args[0];
- static if (__traits(isRef, arg))
- alias fwd = arg;
- else
- @property fwd()(){ return move(arg); }
- alias forward = AliasSeq!(fwd, forward!(args[1..$]));
- }
- else
- alias forward = AliasSeq!();
-}
-
-///
-@safe unittest
-{
- class C
- {
- static int foo(int n) { return 1; }
- static int foo(ref int n) { return 2; }
- }
- int bar()(auto ref int x) { return C.foo(forward!x); }
-
- assert(bar(1) == 1);
- int i;
- assert(bar(i) == 2);
-}
-
-///
-@safe unittest
-{
- void foo(int n, ref string s) { s = null; foreach (i; 0 .. n) s ~= "Hello"; }
-
- // forwards all arguments which are bound to parameter tuple
- void bar(Args...)(auto ref Args args) { return foo(forward!args); }
-
- // forwards all arguments with swapping order
- void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); }
-
- string s;
- bar(1, s);
- assert(s == "Hello");
- baz(s, 2);
- assert(s == "HelloHello");
-}
-
-@safe unittest
-{
- auto foo(TL...)(auto ref TL args)
- {
- string result = "";
- foreach (i, _; args)
- {
- //pragma(msg, "[",i,"] ", __traits(isRef, args[i]) ? "L" : "R");
- result ~= __traits(isRef, args[i]) ? "L" : "R";
- }
- return result;
- }
-
- string bar(TL...)(auto ref TL args)
- {
- return foo(forward!args);
- }
- string baz(TL...)(auto ref TL args)
- {
- int x;
- return foo(forward!args[3], forward!args[2], 1, forward!args[1], forward!args[0], x);
- }
-
- struct S {}
- S makeS(){ return S(); }
- int n;
- string s;
- assert(bar(S(), makeS(), n, s) == "RRLL");
- assert(baz(S(), makeS(), n, s) == "LLRRRL");
-}
-
-@safe unittest
-{
- ref int foo(return ref int a) { return a; }
- ref int bar(Args)(auto ref Args args)
- {
- return foo(forward!args);
- }
- static assert(!__traits(compiles, { auto x1 = bar(3); })); // case of NG
- int value = 3;
- auto x2 = bar(value); // case of OK
+ import core.lifetime : fun = forward;
+ alias forward = fun!args;
}