Binary files /tmp/tmplOhi_Z/EeKv_Az9he/r-cran-rlang-0.4.8/build/rlang.pdf and /tmp/tmplOhi_Z/pDNp3ovBk3/r-cran-rlang-0.4.10/build/rlang.pdf differ diff -Nru r-cran-rlang-0.4.8/debian/changelog r-cran-rlang-0.4.10/debian/changelog --- r-cran-rlang-0.4.8/debian/changelog 2020-10-13 09:28:16.000000000 +0000 +++ r-cran-rlang-0.4.10/debian/changelog 2021-03-02 11:37:52.000000000 +0000 @@ -1,3 +1,16 @@ +r-cran-rlang (0.4.10-1ubuntu1) hirsute; urgency=medium + + * Skip hash tests on big-endian platforms + + -- Graham Inggs Tue, 02 Mar 2021 11:37:52 +0000 + +r-cran-rlang (0.4.10-1) unstable; urgency=medium + + * New upstream version + * Standards-Version: 4.5.1 (routine-update) + + -- Andreas Tille Sat, 16 Jan 2021 16:51:36 +0100 + r-cran-rlang (0.4.8-1) unstable; urgency=medium * New upstream version diff -Nru r-cran-rlang-0.4.8/debian/control r-cran-rlang-0.4.10/debian/control --- r-cran-rlang-0.4.8/debian/control 2020-10-13 09:28:16.000000000 +0000 +++ r-cran-rlang-0.4.10/debian/control 2021-03-02 11:37:52.000000000 +0000 @@ -1,5 +1,6 @@ Source: r-cran-rlang -Maintainer: Debian R Packages Maintainers +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian R Packages Maintainers Uploaders: Andreas Tille Section: gnu-r Testsuite: autopkgtest-pkg-r @@ -7,7 +8,7 @@ Build-Depends: debhelper-compat (= 13), dh-r, r-base-dev -Standards-Version: 4.5.0 +Standards-Version: 4.5.1 Vcs-Browser: https://salsa.debian.org/r-pkg-team/r-cran-rlang Vcs-Git: https://salsa.debian.org/r-pkg-team/r-cran-rlang.git Homepage: https://cran.r-project.org/package=rlang diff -Nru r-cran-rlang-0.4.8/debian/patches/series r-cran-rlang-0.4.10/debian/patches/series --- r-cran-rlang-0.4.8/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/debian/patches/series 2021-03-02 11:35:01.000000000 +0000 @@ -0,0 +1 @@ +skip-hash-tests-on-big-endian.patch diff -Nru r-cran-rlang-0.4.8/debian/patches/skip-hash-tests-on-big-endian.patch r-cran-rlang-0.4.10/debian/patches/skip-hash-tests-on-big-endian.patch --- r-cran-rlang-0.4.8/debian/patches/skip-hash-tests-on-big-endian.patch 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/debian/patches/skip-hash-tests-on-big-endian.patch 2021-03-02 11:37:52.000000000 +0000 @@ -0,0 +1,29 @@ +Description: Skip hash tests on big-endian platforms +Origin: upstream, https://github.com/r-lib/rlang/commit/7c43798eb9fb3b56e9df14b29efb8ae93daadc37 +Author: Davis Vaughan +Last-Update: 2021-01-26 + +--- a/tests/testthat/helper-rlang.R ++++ b/tests/testthat/helper-rlang.R +@@ -44,6 +44,13 @@ + } + }) + ++skip_if_big_endian <- function() { ++ skip_if( ++ identical(.Platform$endian, "big"), ++ "Skipping on big-endian platform." ++ ) ++} ++ + Rscript <- function(args, ...) { + out <- suppressWarnings(system2( + file.path(R.home("bin"), "Rscript"), +--- a/tests/testthat/test-hash.R ++++ b/tests/testthat/test-hash.R +@@ -1,4 +1,5 @@ + test_that("simple hashes with no ALTREP and no attributes are reproducible", { ++ skip_if_big_endian() + expect_identical(hash(1), "a3f7d4a39b65b170005aafbbeed05106") + expect_identical(hash("a"), "4d52a7da68952b85f039e85a90f9bbd2") + expect_identical(hash(1:5 + 0L), "0d26bf75943b8e13c080c6bab12a7440") diff -Nru r-cran-rlang-0.4.8/DESCRIPTION r-cran-rlang-0.4.10/DESCRIPTION --- r-cran-rlang-0.4.8/DESCRIPTION 2020-10-08 10:10:02.000000000 +0000 +++ r-cran-rlang-0.4.10/DESCRIPTION 2020-12-30 15:00:02.000000000 +0000 @@ -1,5 +1,5 @@ Package: rlang -Version: 0.4.8 +Version: 0.4.10 Title: Functions for Base Types and Core R and 'Tidyverse' Features Description: A toolbox for working with base types, core R features like the condition system, and core 'Tidyverse' features like tidy @@ -7,25 +7,37 @@ Authors@R: c( person("Lionel", "Henry", ,"lionel@rstudio.com", c("aut", "cre")), person("Hadley", "Wickham", ,"hadley@rstudio.com", "aut"), + person(given = "mikefc", + email = "mikefc@coolbutuseless.com", + role = "cph", + comment = "Hash implementation based on Mike's xxhashlite"), + person(given = "Yann", + family = "Collet", + role = "cph", + comment = "Author of the embedded xxHash library"), person("RStudio", role = "cph") ) -License: GPL-3 +License: MIT + file LICENSE LazyData: true ByteCompile: true Biarch: true -Depends: R (>= 3.2.0) -Suggests: cli, covr, crayon, glue, magrittr, methods, pillar, - rmarkdown, testthat (>= 2.3.0), vctrs (>= 0.2.3), withr +Depends: R (>= 3.3.0) +Imports: utils +Suggests: cli, covr, crayon, glue, magrittr, methods, pak, pillar, + rmarkdown, testthat (>= 3.0.0), vctrs (>= 0.2.3), withr Enhances: winch Encoding: UTF-8 RoxygenNote: 7.1.1 URL: https://rlang.r-lib.org, https://github.com/r-lib/rlang BugReports: https://github.com/r-lib/rlang/issues +Config/testthat/edition: 3 NeedsCompilation: yes -Packaged: 2020-10-07 10:47:08 UTC; lionel +Packaged: 2020-12-18 09:35:30 UTC; lionel Author: Lionel Henry [aut, cre], Hadley Wickham [aut], + mikefc [cph] (Hash implementation based on Mike's xxhashlite), + Yann Collet [cph] (Author of the embedded xxHash library), RStudio [cph] Maintainer: Lionel Henry Repository: CRAN -Date/Publication: 2020-10-08 10:10:02 UTC +Date/Publication: 2020-12-30 15:00:02 UTC diff -Nru r-cran-rlang-0.4.8/LICENSE r-cran-rlang-0.4.10/LICENSE --- r-cran-rlang-0.4.8/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/LICENSE 2020-12-18 09:00:51.000000000 +0000 @@ -0,0 +1,2 @@ +YEAR: 2020 +COPYRIGHT HOLDER: rlang authors diff -Nru r-cran-rlang-0.4.8/LICENSE.note r-cran-rlang-0.4.10/LICENSE.note --- r-cran-rlang-0.4.8/LICENSE.note 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/LICENSE.note 2020-12-18 09:31:10.000000000 +0000 @@ -0,0 +1,33 @@ +The implementation of `hash()` uses the xxHash library from Yann Collet, which +is released under the BSD 2-Clause license. This library has been embedded into +rlang, without modification, in `src/internal/xxhash/`. A copy of the +BSD 2-Clause license is provided below. + +BSD 2-Clause License ----------------------------------------------------------- + +xxHash Library +Copyright (c) 2012-2020 Yann Collet +All rights reserved. + +BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru r-cran-rlang-0.4.8/man/abort.Rd r-cran-rlang-0.4.10/man/abort.Rd --- r-cran-rlang-0.4.8/man/abort.Rd 2020-07-08 16:23:03.000000000 +0000 +++ r-cran-rlang-0.4.10/man/abort.Rd 2020-11-21 07:26:54.000000000 +0000 @@ -14,7 +14,7 @@ ..., trace = NULL, parent = NULL, - .subclass + .subclass = deprecated() ) warn( @@ -23,7 +23,7 @@ ..., .frequency = c("always", "regularly", "once"), .frequency_id = NULL, - .subclass + .subclass = deprecated() ) inform( @@ -33,20 +33,26 @@ .file = NULL, .frequency = c("always", "regularly", "once"), .frequency_id = NULL, - .subclass + .subclass = deprecated() ) -signal(message, class, ..., .subclass) +signal(message, class, ..., .subclass = deprecated()) interrupt() } \arguments{ -\item{message}{The message to display. - -If not supplied, it is expected that the message is generated -lazily through \link[=cnd_message]{conditionMessage()}. In that case, -\code{class} must be supplied. Only \code{inform()} allows empty messages -as it is occasionally useful to build user output incrementally.} +\item{message}{The message to display. Character vectors are +formatted with \code{\link[=format_error_bullets]{format_error_bullets()}}. The first element +defines a message header and the rest of the vector defines +bullets. Bullets named \code{i} and \code{x} define info and error bullets +respectively, with special Unicode and colour formatting applied +if possible. + +If a message is not supplied, it is expected that the message is +generated lazily through \link[=cnd_message]{conditionMessage()}. In +that case, \code{class} must be supplied. Only \code{inform()} allows empty +messages as it is occasionally useful to build user output +incrementally.} \item{class}{Subclass of the condition. This allows your users to selectively handle the conditions signalled by your functions.} @@ -78,7 +84,10 @@ By default, \code{inform()} prints to standard output in interactive sessions and standard error otherwise. This way IDEs can treat messages distinctly from warnings and errors, and R scripts can -still filter out the messages easily by redirecting \code{stderr}.} +still filter out the messages easily by redirecting \code{stderr}. If +a sink is active, either on output or on messages, messages are +printed to \code{stderr}. This ensures consistency of behaviour in +interactive and non-interactive sessions.} } \description{ These functions are equivalent to base functions \code{\link[base:stop]{base::stop()}}, diff -Nru r-cran-rlang-0.4.8/man/cnd.Rd r-cran-rlang-0.4.10/man/cnd.Rd --- r-cran-rlang-0.4.8/man/cnd.Rd 2020-01-04 15:00:07.000000000 +0000 +++ r-cran-rlang-0.4.10/man/cnd.Rd 2020-11-19 12:47:54.000000000 +0000 @@ -7,19 +7,16 @@ \alias{message_cnd} \title{Create a condition object} \usage{ -error_cnd(.subclass = NULL, ..., message = "", trace = NULL, parent = NULL) +error_cnd(class = NULL, ..., message = "", trace = NULL, parent = NULL) -cnd(class, ..., message = "", .subclass) +cnd(class, ..., message = "") -warning_cnd(class = NULL, ..., message = "", .subclass) +warning_cnd(class = NULL, ..., message = "") -message_cnd(class = NULL, ..., message = "", .subclass) +message_cnd(class = NULL, ..., message = "") } \arguments{ -\item{.subclass}{This argument was renamed to \code{class} in rlang -0.4.2. It will be deprecated in the next major version. This is -for consistency with our conventions for class constructors -documented in \url{https://adv-r.hadley.nz/s3.html#s3-subclassing}.} +\item{class}{The condition subclass.} \item{...}{<\link[=dyn-dots]{dynamic}> Named data fields stored inside the condition object.} @@ -30,8 +27,6 @@ \item{trace}{A \code{trace} object created by \code{\link[=trace_back]{trace_back()}}.} \item{parent}{A parent condition object created by \code{\link[=abort]{abort()}}.} - -\item{class}{The condition subclass.} } \description{ These constructors make it easy to create subclassed conditions. @@ -43,13 +38,6 @@ created with \code{error_cnd()}, \code{warning_cnd()} and \code{message_cnd()} inherit from \code{error}, \code{warning} or \code{message}. } -\section{Lifecycle}{ - - -The \code{.type} and \code{.msg} arguments have been renamed to \code{.subclass} -and \code{message}. They are deprecated as of rlang 0.3.0. -} - \examples{ # Create a condition inheriting from the s3 type "foo": cnd <- cnd("foo") diff -Nru r-cran-rlang-0.4.8/man/cnd_signal.Rd r-cran-rlang-0.4.10/man/cnd_signal.Rd --- r-cran-rlang-0.4.8/man/cnd_signal.Rd 2019-10-23 08:50:38.000000000 +0000 +++ r-cran-rlang-0.4.10/man/cnd_signal.Rd 2020-11-19 12:47:54.000000000 +0000 @@ -4,12 +4,13 @@ \alias{cnd_signal} \title{Signal a condition object} \usage{ -cnd_signal(cnd, .cnd, .mufflable) +cnd_signal(cnd, ...) } \arguments{ -\item{cnd}{A condition object (see \code{\link[=cnd]{cnd()}}).} +\item{cnd}{A condition object (see \code{\link[=cnd]{cnd()}}). If \code{NULL}, +\code{cnd_signal()} returns without signalling a condition.} -\item{.cnd, .mufflable}{These arguments are deprecated.} +\item{...}{These dots are for extensions and must be empty.} } \description{ The type of signal depends on the class of the condition: @@ -30,18 +31,6 @@ Use \code{\link[=cnd_type]{cnd_type()}} to determine the type of a condition. } -\section{Lifecycle}{ - -\itemize{ -\item \code{.cnd} has been renamed to \code{cnd} and is deprecated as of rlang 0.3.0. -\item The \code{.mufflable} argument is deprecated as of rlang 0.3.0 and no -longer has any effect. Non-critical conditions are always -signalled with a muffle restart. -\item Creating a condition object with \code{\link[=cnd_signal]{cnd_signal()}} is deprecated as -of rlang 0.3.0. Please use \code{\link[=signal]{signal()}} instead. -} -} - \examples{ # The type of signal depends on the class. If the condition # inherits from "warning", a warning is issued: diff -Nru r-cran-rlang-0.4.8/man/dyn-dots.Rd r-cran-rlang-0.4.10/man/dyn-dots.Rd --- r-cran-rlang-0.4.8/man/dyn-dots.Rd 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/man/dyn-dots.Rd 2020-12-18 09:00:51.000000000 +0000 @@ -16,8 +16,9 @@ Dynamic dots offer a few additional features: \enumerate{ \item You can \strong{splice} arguments saved in a list with the \link[=quasiquotation]{big bang} operator \verb{!!!}. -\item You can \strong{unquote} names by using the \link[=quasiquotation]{bang bang} -operator \verb{!!} on the left-hand side of \verb{:=}. +\item You can \strong{unquote} names by using the \link[glue:glue]{glue} syntax +or the \link[=quasiquotation]{bang bang} operator \verb{!!} on the +left-hand side of \verb{:=}. \item Trailing commas are ignored, making it easier to copy and paste lines of arguments. } @@ -31,6 +32,9 @@ Other dynamic dots collectors are \code{\link[=dots_list]{dots_list()}}, which is more configurable than \code{\link[=list2]{list2()}}, \code{vars()} which doesn't force its arguments, and \code{\link[=call2]{call2()}} for creating calls. + +Document dynamic docs using this standard tag:\preformatted{ @param ... <[`dynamic-dots`][rlang::dyn-dots]> What these dots do. +} } \examples{ diff -Nru r-cran-rlang-0.4.8/man/enquo0.Rd r-cran-rlang-0.4.10/man/enquo0.Rd --- r-cran-rlang-0.4.8/man/enquo0.Rd 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/man/enquo0.Rd 2020-11-19 15:26:46.000000000 +0000 @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/nse-defuse.R +\name{enquo0} +\alias{enquo0} +\alias{enquos0} +\title{Defuse arguments without automatic injection} +\usage{ +enquo0(arg) + +enquos0(...) +} +\arguments{ +\item{arg}{A symbol for a function argument to defuse.} + +\item{...}{Dots to defuse.} +} +\description{ +The 0-suffixed variants of \code{\link[=enquo]{enquo()}} and \code{\link[=enquos]{enquos()}} defuse function +arguments without automatic injection (unquotation). They are +useful when defusing expressions that potentially include \verb{!!}, +\verb{!!!}, or \verb{\{\{} operations, for instance tidyverse code. In that +case, \code{enquo()} would process these operators too early, creating a +confusing experience for users. Callers can still inject objects +or expressions using manual injection with \code{\link[=inject]{inject()}}. +} +\details{ +None of the features of \link[=dyn-dots]{dynamic dots} are available when +defusing with \code{enquos0()}. For instance, trailing empty arguments +are not automatically trimmed. +} +\examples{ +automatic_injection <- function(x) enquo(x) +no_injection <- function(x) enquo0(x) + +automatic_injection(foo(!!!1:3)) +no_injection(foo(!!!1:3)) +} +\seealso{ +\code{\link[=enquo]{enquo()}} and \code{\link[=enquos]{enquos()}} +} diff -Nru r-cran-rlang-0.4.8/man/entrace.Rd r-cran-rlang-0.4.10/man/entrace.Rd --- r-cran-rlang-0.4.8/man/entrace.Rd 2019-10-23 08:53:46.000000000 +0000 +++ r-cran-rlang-0.4.10/man/entrace.Rd 2020-12-18 09:00:51.000000000 +0000 @@ -39,7 +39,7 @@ condition object, without any other effect. Both functions should be called directly from an error handler. -Set the \code{error} global option to \code{quote(rlang::entrace())} to +Set the \code{error} global option to \code{rlang::entrace} to transform base errors to rlang errors. These enriched errors include a backtrace. The RProfile is a good place to set the handler. See \code{\link{rlang_backtrace_on_error}} for details. diff -Nru r-cran-rlang-0.4.8/man/env_bind.Rd r-cran-rlang-0.4.10/man/env_bind.Rd --- r-cran-rlang-0.4.8/man/env_bind.Rd 2020-06-26 13:10:13.000000000 +0000 +++ r-cran-rlang-0.4.10/man/env_bind.Rd 2020-11-23 12:47:48.000000000 +0000 @@ -4,6 +4,7 @@ \alias{env_bind} \alias{env_bind_lazy} \alias{env_bind_active} +\alias{\%<~\%} \title{Bind symbols to objects in an environment} \usage{ env_bind(.env, ...) @@ -11,6 +12,8 @@ env_bind_lazy(.env, ..., .eval_env = caller_env()) env_bind_active(.env, ...) + +lhs \%<~\% rhs } \arguments{ \item{.env}{An environment.} @@ -21,6 +24,10 @@ \item{.eval_env}{The environment where the expressions will be evaluated when the symbols are forced.} + +\item{lhs}{The variable name to which \code{rhs} will be lazily assigned.} + +\item{rhs}{An expression lazily evaluated and assigned to \code{lhs}.} } \value{ The input object \code{.env}, with its associated environment @@ -56,6 +63,8 @@ corresponding expression is evaluated in turn and its value is bound to the symbol (the expressions are thus evaluated only once, if at all). +\item \verb{\%<~\%} is a shortcut for \code{env_bind_lazy()}. It works like \verb{<-} +but the RHS is evaluated lazily. } } \section{Side effects}{ diff -Nru r-cran-rlang-0.4.8/man/env_browse.Rd r-cran-rlang-0.4.10/man/env_browse.Rd --- r-cran-rlang-0.4.8/man/env_browse.Rd 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/man/env_browse.Rd 2020-11-19 12:47:54.000000000 +0000 @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/env.R +\name{env_browse} +\alias{env_browse} +\alias{env_is_browsed} +\title{Browse environments} +\usage{ +env_browse(env, value = TRUE) + +env_is_browsed(env) +} +\arguments{ +\item{env}{An environment.} + +\item{value}{Whether to browse \code{env}.} +} +\value{ +\code{env_browse()} returns the previous value of +\code{env_is_browsed()} (a logical), invisibly. +} +\description{ +\itemize{ +\item \code{env_browse(env)} is equivalent to evaluating \code{browser()} in +\code{env}. It persistently sets the environment for step-debugging. +Supply \code{value = FALSE} to disable browsing. +\item \code{env_is_browsed()} is a predicate that inspects whether an +environment is being browsed. +} +} diff -Nru r-cran-rlang-0.4.8/man/env_has.Rd r-cran-rlang-0.4.10/man/env_has.Rd --- r-cran-rlang-0.4.8/man/env_has.Rd 2018-12-17 14:37:51.000000000 +0000 +++ r-cran-rlang-0.4.10/man/env_has.Rd 2020-11-20 10:27:04.000000000 +0000 @@ -9,8 +9,8 @@ \arguments{ \item{env}{An environment.} -\item{nms}{A character vector containing the names of the bindings -to remove.} +\item{nms}{A character vector of binding names for which to check +existence.} \item{inherit}{Whether to look for bindings in the parent environments.} diff -Nru r-cran-rlang-0.4.8/man/env_print.Rd r-cran-rlang-0.4.10/man/env_print.Rd --- r-cran-rlang-0.4.8/man/env_print.Rd 2020-01-04 15:00:08.000000000 +0000 +++ r-cran-rlang-0.4.10/man/env_print.Rd 2020-11-20 15:44:31.000000000 +0000 @@ -22,4 +22,10 @@ indicated as such. \item Locked bindings get a \verb{[L]} tag } + +Note that printing a package namespace (see \code{\link[=ns_env]{ns_env()}}) with +\code{env_print()} will typically tag function bindings as \verb{} +until they are evaluated the first time. This is because package +functions are lazily-loaded from disk to improve performance when +loading a package. } diff -Nru r-cran-rlang-0.4.8/man/env_unbind.Rd r-cran-rlang-0.4.10/man/env_unbind.Rd --- r-cran-rlang-0.4.8/man/env_unbind.Rd 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/man/env_unbind.Rd 2020-11-20 10:27:04.000000000 +0000 @@ -9,8 +9,7 @@ \arguments{ \item{env}{An environment.} -\item{nms}{A character vector containing the names of the bindings -to remove.} +\item{nms}{A character vector of binding names to remove.} \item{inherit}{Whether to look for bindings in the parent environments.} diff -Nru r-cran-rlang-0.4.8/man/eval_tidy.Rd r-cran-rlang-0.4.10/man/eval_tidy.Rd --- r-cran-rlang-0.4.8/man/eval_tidy.Rd 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/man/eval_tidy.Rd 2020-12-18 09:00:51.000000000 +0000 @@ -94,14 +94,18 @@ \section{Stack semantics of \code{eval_tidy()}}{ -\code{eval_tidy()} has different stack semantics than \code{\link[base:eval]{base::eval()}}: +\code{eval_tidy()} always evaluates in a data mask, even when \code{data} is +\code{NULL}. Because of this, it has different stack semantics than +\code{\link[base:eval]{base::eval()}}: \itemize{ +\item Lexical side effects, such as assignment with \verb{<-}, occur in the +mask rather than \code{env}. \item Functions that require the evaluation environment to correspond to a frame on the call stack do not work. This is why \code{return()} called from a quosure does not work. -\item The mask environment creates a new branch in the call tree -defined by \code{sys.parent()} (you can visualise it in a \code{\link[=browser]{browser()}} -session with \code{lobstr::cst()}). +\item The mask environment creates a new branch in the tree +representation of backtraces (which you can visualise in a +\code{\link[=browser]{browser()}} session with \code{lobstr::cst()}). } See also \code{\link[=eval_bare]{eval_bare()}} for more information about these differences. diff -Nru r-cran-rlang-0.4.8/man/format_error_bullets.Rd r-cran-rlang-0.4.10/man/format_error_bullets.Rd --- r-cran-rlang-0.4.8/man/format_error_bullets.Rd 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/man/format_error_bullets.Rd 2020-11-20 15:31:46.000000000 +0000 @@ -11,8 +11,6 @@ \code{x} or \code{i} are prefixed with the corresponding bullet.} } \description{ -\Sexpr[results=rd, stage=render]{rlang:::lifecycle("experimental")} - \code{format_error_bullets()} takes a character vector and returns a single string (or an empty vector if the input is empty). The elements of the input vector are assembled as a list of bullets, depending on diff -Nru r-cran-rlang-0.4.8/man/hash.Rd r-cran-rlang-0.4.10/man/hash.Rd --- r-cran-rlang-0.4.8/man/hash.Rd 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/man/hash.Rd 2020-12-18 09:31:10.000000000 +0000 @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/hash.R +\name{hash} +\alias{hash} +\title{Hash an object} +\usage{ +hash(x) +} +\arguments{ +\item{x}{An object.} +} +\description{ +\code{hash()} hashes an arbitrary R object. + +The generated hash is guaranteed to be reproducible across platforms, but +not across R versions. +} +\details{ +\code{hash()} uses the XXH128 hash algorithm of the xxHash library, which +generates a 128-bit hash. It is implemented as a streaming hash, which +generates the hash with minimal extra memory usage. + +Objects are converted to binary using R's native serialization tools. +On R >= 3.5.0, serialization version 3 is used, otherwise version 2 is used. +See \code{\link[=serialize]{serialize()}} for more information about the serialization version. +} +\examples{ +hash(c(1, 2, 3)) +hash(mtcars) +} diff -Nru r-cran-rlang-0.4.8/man/inject.Rd r-cran-rlang-0.4.10/man/inject.Rd --- r-cran-rlang-0.4.8/man/inject.Rd 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/man/inject.Rd 2020-11-19 15:26:46.000000000 +0000 @@ -0,0 +1,50 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/eval.R +\name{inject} +\alias{inject} +\title{Inject objects in an R expression} +\usage{ +inject(expr, env = caller_env()) +} +\arguments{ +\item{expr}{An argument to evaluate. This argument is immediately +evaluated in \code{env} (the current environment by default) with +injected objects and expressions.} + +\item{env}{The environment in which to evaluate \code{expr}. Defaults to +the current environment. For expert use only.} +} +\description{ +\code{inject()} evaluates an expression with \link[=quasiquotation]{injection} +(unquotation) support. There are three main usages: +} +\details{ +\itemize{ +\item \link[=!!!]{Splicing} lists of arguments in a function call. +\item Inline objects or other expressions in an expression with \verb{!!} +and \verb{!!!}. For instance to create functions or formulas +programmatically. +\item Pass arguments to NSE functions that \link[=nse-defuse]{defuse} their +arguments without injection support (see for instance +\code{\link[=enquo0]{enquo0()}}). You can use \code{{{ arg }}} with functions documented +to support quosures. Otherwise, use \code{!!enexpr(arg)}. +} +} +\examples{ +# inject() simply evaluates its argument with injection +# support. These expressions are equivalent: +2 * 3 +inject(2 * 3) +inject(!!2 * !!3) + +# Injection with `!!` can be useful to insert objects or +# expressions within other expressions, like formulas: +lhs <- sym("foo") +rhs <- sym("bar") +inject(!!lhs ~ !!rhs + 10) + +# Injection with `!!!` splices lists of arguments in function +# calls: +args <- list(na.rm = TRUE, finite = 0.2) +inject(mean(1:10, !!!args)) +} diff -Nru r-cran-rlang-0.4.8/man/is_installed.Rd r-cran-rlang-0.4.10/man/is_installed.Rd --- r-cran-rlang-0.4.8/man/is_installed.Rd 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/man/is_installed.Rd 2020-12-18 09:00:51.000000000 +0000 @@ -2,20 +2,41 @@ % Please edit documentation in R/env-special.R \name{is_installed} \alias{is_installed} +\alias{check_installed} \title{Are packages installed in any of the libraries?} \usage{ is_installed(pkg) + +check_installed(pkg, reason = NULL) } \arguments{ \item{pkg}{The package names.} + +\item{reason}{Optional string indicating why is \code{pkg} needed. +Appears in error messages (if non-interactive) and user prompts +(if interactive).} } \value{ -\code{TRUE} if \emph{all} package names provided in \code{pkg} are installed, -\code{FALSE} otherwise. +\code{is_installed()} returns \code{TRUE} if \emph{all} package names +provided in \code{pkg} are installed, \code{FALSE} +otherwise. \code{check_installed()} either doesn't return or returns +\code{NULL}. } \description{ -This checks that packages are installed with minimal side effects. -If installed, the packages will be loaded but not attached. +These functions check that packages are installed with minimal side +effects. If installed, the packages will be loaded but not +attached. +\itemize{ +\item \code{is_installed()} doesn't interact with the user. It simply +returns \code{TRUE} or \code{FALSE} depending on whether the packages are +installed. +\item In interactive sessions, \code{check_installed()} asks the user +whether to install missing packages. If the user accepts, the +packages are installed with \code{pak::pkg_install()} if available, or +\code{\link[utils:install.packages]{utils::install.packages()}} otherwise. If the session is non +interactive or if the user chooses not to install the packages, +the current evaluation is aborted. +} } \examples{ is_installed("utils") diff -Nru r-cran-rlang-0.4.8/man/nse-defuse.Rd r-cran-rlang-0.4.10/man/nse-defuse.Rd --- r-cran-rlang-0.4.8/man/nse-defuse.Rd 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/man/nse-defuse.Rd 2020-11-19 15:01:15.000000000 +0000 @@ -274,3 +274,7 @@ # expected result: eval_tidy(quo) } +\seealso{ +\code{\link[=enquo0]{enquo0()}} and \code{\link[=enquos0]{enquos0()}} for variants that do not +perform automatic injection/unquotation. +} diff -Nru r-cran-rlang-0.4.8/man/parse_expr.Rd r-cran-rlang-0.4.10/man/parse_expr.Rd --- r-cran-rlang-0.4.8/man/parse_expr.Rd 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/man/parse_expr.Rd 2020-11-23 12:47:48.000000000 +0000 @@ -3,17 +3,28 @@ \name{parse_expr} \alias{parse_expr} \alias{parse_exprs} +\alias{parse_quo} +\alias{parse_quos} \title{Parse R code} \usage{ parse_expr(x) parse_exprs(x) + +parse_quo(x, env = global_env()) + +parse_quos(x, env = global_env()) } \arguments{ \item{x}{Text containing expressions to parse_expr for \code{parse_expr()} and \code{parse_exprs()}. Can also be an R connection, for instance to a file. If the supplied connection is not open, it will be automatically closed and destroyed.} + +\item{env}{The environment for the quosures. The \link[=global_env]{global environment} (the default) may be the right choice +when you are parsing external user inputs. You might also want to +evaluate the R code in an isolated context (perhaps a child of +the global environment or of the \link[=base_env]{base environment}).} } \value{ \code{parse_expr()} returns an \link[=is_expression]{expression}, @@ -22,19 +33,31 @@ length of the input. This would happen is one of the strings contain several expressions (such as \code{"foo; bar"}). The names of \code{x} are preserved (and recycled in case of multiple expressions). +The \verb{_quo} suffixed variants return quosures. } \description{ These functions parse and transform text into R expressions. This is the first step to interpret or evaluate a piece of R code written by a programmer. +\itemize{ +\item \code{parse_expr()} returns one expression. If the text contains more +than one expression (separated by semicolons or new lines), an +error is issued. On the other hand \code{parse_exprs()} can handle +multiple expressions. It always returns a list of expressions +(compare to \code{\link[base:parse]{base::parse()}} which returns a base::expression +vector). All functions also support R connections. +\item \code{parse_quo()} and \code{parse_quos()} are variants that create a +\link[=quo]{quosure} that inherits from the global environment by +default. This is appropriate when you're parsing external user +input to be evaluated in user context (rather than the private +contexts of your functions). + +Unlike quosures created with \code{\link[=enquo]{enquo()}}, \code{\link[=enquos]{enquos()}}, or \verb{\{\{}, a +parsed quosure never contains injected quosures. It is thus safe +to evaluate them with \code{eval()} instead of \code{\link[=eval_tidy]{eval_tidy()}}, though +the latter is more convenient as you don't need to extract \code{expr} +and \code{env}. } -\details{ -\code{parse_expr()} returns one expression. If the text contains more -than one expression (separated by semicolons or new lines), an error is -issued. On the other hand \code{parse_exprs()} can handle multiple -expressions. It always returns a list of expressions (compare to -\code{\link[base:parse]{base::parse()}} which returns a base::expression vector). All -functions also support R connections. } \examples{ # parse_expr() can parse any R expression: diff -Nru r-cran-rlang-0.4.8/man/parse_quo.Rd r-cran-rlang-0.4.10/man/parse_quo.Rd --- r-cran-rlang-0.4.8/man/parse_quo.Rd 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/man/parse_quo.Rd 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/parse.R -\name{parse_quo} -\alias{parse_quo} -\alias{parse_quos} -\title{Parsing variants that return quosures} -\usage{ -parse_quo(x, env) - -parse_quos(x, env) -} -\arguments{ -\item{x}{Text containing expressions to parse_expr for -\code{parse_expr()} and \code{parse_exprs()}. Can also be an R connection, -for instance to a file. If the supplied connection is not open, -it will be automatically closed and destroyed.} - -\item{env}{The environment for the quosures. Depending on the use -case, a good default might be the \link[=global_env]{global environment} but you might also want to evaluate the -R code in an isolated context (perhaps a child of the global -environment or of the \link[=base_env]{base environment}).} -} -\description{ -\Sexpr[results=rd, stage=render]{rlang:::lifecycle("questioning")} - -These functions are in the questioning stage because they don't add -value compared to using \code{\link[=parse_expr]{parse_expr()}} with \code{\link[=new_quosure]{new_quosure()}}. -} -\keyword{internal} diff -Nru r-cran-rlang-0.4.8/man/parse_quosure.Rd r-cran-rlang-0.4.10/man/parse_quosure.Rd --- r-cran-rlang-0.4.8/man/parse_quosure.Rd 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/man/parse_quosure.Rd 2020-11-23 12:47:48.000000000 +0000 @@ -14,6 +14,11 @@ \code{parse_expr()} and \code{parse_exprs()}. Can also be an R connection, for instance to a file. If the supplied connection is not open, it will be automatically closed and destroyed.} + +\item{env}{The environment for the quosures. The \link[=global_env]{global environment} (the default) may be the right choice +when you are parsing external user inputs. You might also want to +evaluate the R code in an isolated context (perhaps a child of +the global environment or of the \link[=base_env]{base environment}).} } \description{ \Sexpr[results=rd, stage=render]{rlang:::lifecycle("deprecated")} diff -Nru r-cran-rlang-0.4.8/man/search_envs.Rd r-cran-rlang-0.4.10/man/search_envs.Rd --- r-cran-rlang-0.4.8/man/search_envs.Rd 2020-01-04 15:00:07.000000000 +0000 +++ r-cran-rlang-0.4.10/man/search_envs.Rd 2020-11-19 12:47:54.000000000 +0000 @@ -51,6 +51,9 @@ environment of packages if they are attached to the search path, and throws an error otherwise. It is a shortcut for \code{search_env(pkg_env_name("pkgname"))}. +\item \code{global_env()} and \code{base_env()} (simple aliases for \code{\link[=globalenv]{globalenv()}} +and \code{\link[=baseenv]{baseenv()}}). These are respectively the first and last +environments of the search path. \item \code{is_attached()} returns \code{TRUE} when its argument (a search name or a package environment) is attached to the search path. } @@ -62,8 +65,8 @@ the global workspace. It contains the following elements: \itemize{ \item The chain always starts with \code{global_env()} and finishes with -\code{base_env()} (technically, it finishes with the \code{empty_env()} -which the base package environment inherits from). +\code{base_env()} which inherits from the terminal environment +\code{empty_env()}. \item Each \code{\link[base:library]{base::library()}} call attaches a new package environment to the search path. Attached packages are associated with a \link[=env_name]{search name}. \item In addition, any list, data frame, or environment can be attached diff -Nru r-cran-rlang-0.4.8/man/tidyeval-data.Rd r-cran-rlang-0.4.10/man/tidyeval-data.Rd --- r-cran-rlang-0.4.8/man/tidyeval-data.Rd 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/man/tidyeval-data.Rd 2020-11-20 10:21:22.000000000 +0000 @@ -6,9 +6,6 @@ \alias{.data} \alias{.env} \title{Data pronouns for tidy evaluation} -\format{ -An object of class \code{rlang_fake_data_pronoun} of length . -} \usage{ .data diff -Nru r-cran-rlang-0.4.8/man/zap_srcref.Rd r-cran-rlang-0.4.10/man/zap_srcref.Rd --- r-cran-rlang-0.4.8/man/zap_srcref.Rd 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/man/zap_srcref.Rd 2020-11-20 10:06:03.000000000 +0000 @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/attr.R +\name{zap_srcref} +\alias{zap_srcref} +\title{Zap source references} +\usage{ +zap_srcref(x) +} +\arguments{ +\item{x}{An R object. Functions and calls are walked recursively.} +} +\description{ +There are a number of situations where R creates source references: +\itemize{ +\item Reading R code from a file with \code{source()} and \code{parse()} might save +source references inside calls to \code{function} and \verb{\{}. +\item \code{\link[=sys.call]{sys.call()}} includes a source reference if possible. +\item Creating a closure stores the source reference from the call to +\code{function}, if any. +} + +These source references take up space and might cause a number of +issues. \code{zap_srcref()} recursively walks through expressions and +functions to remove all source references. +} diff -Nru r-cran-rlang-0.4.8/MD5 r-cran-rlang-0.4.10/MD5 --- r-cran-rlang-0.4.8/MD5 2020-10-08 10:10:02.000000000 +0000 +++ r-cran-rlang-0.4.10/MD5 2020-12-30 15:00:02.000000000 +0000 @@ -1,17 +1,20 @@ -ec7a764774946f85cc18f209e8d09eb6 *DESCRIPTION -85be91cdce24edaa09ef3c0b9a8267ea *NAMESPACE -079538a94c42314b4ece0f51f7b6df69 *NEWS.md -dc124d12cc69d1bce1d8634ae76e8109 *R/arg.R -2873fb2215392a12981e5b9569e97a4d *R/attr.R -a3c139164a018ee838dfa452e96e8f95 *R/call.R -ee99883105cb77a0b0049f02b5df5424 *R/cnd-abort.R -d204a66c0cdc0cb113e79968a9b1e755 *R/cnd-entrace.R -93c992e2b1b7a366056d51cd3932dc5b *R/cnd-error.R -13233a808dd462584154fcc1642149e5 *R/cnd-handlers.R -7710303257b3e296ddc24ced10fb20dd *R/cnd-message.R +969d032063ba9c6f1bd42d1918e5dd28 *DESCRIPTION +e6f43178fbfc71c5d0c6586954b66df1 *LICENSE +571f9fded5d43695ad11e04790c0af64 *LICENSE.note +957b7e98f5210e498e06ad9408b0d912 *NAMESPACE +7272b23413703d439d6a20fcd4db94d2 *NEWS.md +f07e13cb51f43acdc1f906333f9fd11b *R/aaa.R +b49bbfe374a6a74c44e56d558bd31420 *R/arg.R +4a64d177fa898904b3abe77c5d44c0eb *R/attr.R +96a1208db367a5cbe7ac018bbcb42c8b *R/call.R +ae8f86025b1cd430116138466e83b51e *R/cnd-abort.R +27f65ea250f5eb981c4650f41bb18e1a *R/cnd-entrace.R +adf17bb6e96a3e3850744e1758722fa8 *R/cnd-error.R +f7fe941de28611d73f86fd1eebee2191 *R/cnd-handlers.R +89c13d78d38b33b9b42caa0ae8866d64 *R/cnd-message.R 5076c1dd518a74b797ab6d714482e662 *R/cnd-restarts.R -bfc83b0e016974bd1881db714f4b0d9f *R/cnd-signal.R -ca31ea99129ea5a2f3c2fbe50cc7baab *R/cnd.R +4c28aefa3932ba6664990f81c941edc7 *R/cnd-signal.R +f7e4c5a8f06749679fac90b3f0274be5 *R/cnd.R b7ec20d63149f2593c59a8a7cc058171 *R/compat-defer.R c5da9b45224153c3b2cb2e2c842e7e6a *R/compat-downstream-dep.R e5a9676fa2b27c9a20ed34b04731c271 *R/compat-friendly-type.R @@ -21,27 +24,29 @@ 552b6c37e0f78fa99b9233101a2c59f7 *R/compat-oldrel.R 6ff61ce96b8a0aca5f241ef7aaab4a68 *R/compat-purrr.R 4de02456d59484fb66db37255e5b1b4f *R/compat-register.R -49ebfbeb8d39f6513126539b8daf8f51 *R/deparse.R -48436f601316b163626655b99883a83b *R/dots.R -b969955047bf64126d93a7f2e3362a91 *R/env-binding.R -5e1cb7c16be702e680b8657d7e747d60 *R/env-special.R -ec295783dd410c7ed0b464ba10e63a65 *R/env.R -a71ed5c687581a15ca77f10dd5d8c7d5 *R/eval-tidy.R -d3a0e1e75f081adbf1d989257764585f *R/eval.R +d3c7cc3bb18bb727df9f8fb8b8d9df03 *R/compat-zeallot.R +ea9b0a3266e69d361babd9142d68cf80 *R/deparse.R +25b71916d297c8192b488fb85b0fe4f7 *R/dots.R +e7c533f64dc9945396376befac84f0b9 *R/env-binding.R +b9f6e458c42303a9618795de9951866b *R/env-special.R +35e2d549a25bd492203ff61b33ebdc39 *R/env.R +004638e7b5e3b11e417e0bd08b5c4fea *R/eval-tidy.R +5f614e15a906ddc7a32ec6892bad2860 *R/eval.R c661ba6708a5366d94d986d9c7ec9afc *R/expr.R e668771a8785ba80c053d2e11f29c4a8 *R/faq.R -a2b3b4842eaf0e303db0ad2b3bd7b4b9 *R/fn.R +c3a9b3c7678d2fcf50ac5ef3d0f8e499 *R/fn.R a1671e632cd11bee51ce27f63190c762 *R/formula.R -dfeb506d5344f361f61a50e621d56d82 *R/lifecycle-retired.R -a21ffe4ce5e9cb71d0e3e38e2075c5c3 *R/lifecycle.R -6ff4b8a977da094ce237086ad0138647 *R/node.R -fb383f8859092c64c931aa4bb02200c2 *R/nse-defuse.R +c668bf6844971cf2ddc8814de24c347c *R/hash.R +a24f83993902435e92fd65a5a9f86004 *R/lifecycle-retired.R +06ef2fda8a0b6421b94e9fbbe4172843 *R/lifecycle.R +323978027f77d2d7b55ea55ab25a649c *R/node.R +e84932aaf80d214554c98de65f6e66d9 *R/nse-defuse.R c1080dd88ebadff89b17864b0022703f *R/nse-force.R 47af234c7ee15b4574843aeff1ecdc54 *R/operators.R -bb1e77532284929653ddb5a797ec755b *R/parse.R +1291c9205d145c43541c73f9f042770f *R/parse.R 192594dd3a7f80cadf900cfdac9c7ff2 *R/quo.R b5480a843d4618a2f687081499a49b9d *R/raw.R -2b7a1d4e4c40cd4b6325f29a39163d20 *R/rlang.R +8e5e212055cf62c2e9a4c4089ce7e011 *R/rlang.R d71f445da3e9a1934369e35a669b0a96 *R/s3.R fa99c70ade80fffae85ab29fc6fbca0d *R/sexp.R 72f397950f0f33bf1421c1caf7bfb714 *R/stack.R @@ -52,16 +57,16 @@ 1b35c98262b47382e00066635ea67e16 *R/utils-cli-tree.R a4eb7beca392f730c331d203124ef20e *R/utils-conditions.R 520e5f54bc830142895d5f7f30d7af82 *R/utils-encoding.R -81e754fbcf1ab7f6cce1836825d1ee26 *R/utils.R +052c2951dd34fbd6f02f5000c8797358 *R/utils.R ccc317028acdcef6c838e80a69f5c17b *R/vec-na.R ee59231a415a456645cce45c958f98a5 *R/vec-new.R c385c983f67b71461d7b0951db6a9c5d *R/vec-squash.R 7abd99704c8a9dec7e55651158cc2853 *R/vec.R 5835c34bf4379eb86b6257fd9dce56d7 *R/weakref.R b68c0d39aaf77f4b914576e9600488fe *README.md -45eb05ee766220099c144b05ec31472f *build/rlang.pdf +5bacde6cc01691040c8c0f99882a89c9 *build/rlang.pdf c9e47dbb0e1927076ed7b2e1ec157be7 *inst/backtrace-ver -2cbeaca67800c5f5f65cf406dc981f6a *man/abort.Rd +71ac8969b603b879fd01d9ed7cd0b231 *man/abort.Rd 3978bd918c9341b59c6ca11082c33cc7 *man/are_na.Rd 3da5ccfa58a2143af2729773b8f3bf88 *man/arg_match.Rd 4b77a5dcfe61ef4fb2dfd345efc5179e *man/as_box.Rd @@ -92,40 +97,42 @@ 296ed78ac6c8afe2f4b7135b423f730b *man/caller_frame.Rd fbb49d5cbc765200fef6ff0dfb754a5e *man/catch_cnd.Rd f0357139f4ff3aa04f404cec96bf28b3 *man/chr_unserialise_unicode.Rd -c358c2cab5adaaeab1d048b8eb6585a2 *man/cnd.Rd +ac4a2b14a1e0db71d2628e147f8427d4 *man/cnd.Rd 639f0f7f6c43dcb5f583fa6983454ce3 *man/cnd_message.Rd 69900ac92ce74840441df33d7ab9e943 *man/cnd_muffle.Rd -caa0076108771b239c58a450cae0dbd6 *man/cnd_signal.Rd +9200e629d71dbf5b337c738108a067c4 *man/cnd_signal.Rd ff04cda4427d58d29adffe62584a893c *man/cnd_type.Rd 8654e8dc8b768c62606b06b23d468697 *man/done.Rd 9a4f9e3bc58705a5305ea6b5ec4e2a06 *man/dots_definitions.Rd eeb1597b3c596c220fc4d98aff8c387b *man/dots_n.Rd da1f1192db1ed365d6bec9970feb8b80 *man/dots_values.Rd ed4c24f851aeae3ba1c17434e3171742 *man/duplicate.Rd -43c648afa15180781556938d512092de *man/dyn-dots.Rd +d759f0d045bafd8350252c561cf10056 *man/dyn-dots.Rd 16d5c0a4d87193d62a935037549cb822 *man/empty_env.Rd -b5153c919b659bae705838251e9cac2f *man/entrace.Rd +b291cad60518f436451a32b16f7ea53b *man/enquo0.Rd +18e4aef1456c273f1b847964086ed776 *man/entrace.Rd 28db52ffec8defd429da43591ee6adf8 *man/env.Rd -36977d4a9a48fa0526a0b279538ff278 *man/env_bind.Rd +0e3f3596d4a292b12e1474ae30e9a814 *man/env_bind.Rd 67fd1c9b0b2130527fdb469b33f6a402 *man/env_bind_exprs.Rd 4765a839bd99a74d99b86dfbb3d45e0d *man/env_binding_are_active.Rd 449b54ab5b12a6bef4d2812cd2094547 *man/env_binding_lock.Rd +307c267709302c23b56c7a7bc230d8fa *man/env_browse.Rd 25a6b39750d0ff0d7c98c6f3cca6ec78 *man/env_bury.Rd 99fc970e815450263d94f5a781dd1dbe *man/env_clone.Rd f330df1e53699e936dabc4617079c438 *man/env_depth.Rd 89e5527fc2edf344b2ce98c16c1b8430 *man/env_get.Rd -e550d9e9d0461ea5dd7104b8e5bfb58c *man/env_has.Rd +b9520b5a9c45754cb75a7dfd41c467a3 *man/env_has.Rd 2e4b15ff1b9f7d608dbaff7e1efc6399 *man/env_inherits.Rd ccade1888c23c36a05de52a40b3b4e54 *man/env_lock.Rd 5bee84cd96d0aa2d27af6ac6346ce9f0 *man/env_name.Rd 874a7a42f2f3714957ba6e2d743420a7 *man/env_names.Rd 3cc0675314ceabdf5622ec981363172d *man/env_parent.Rd fa234e4b03677b92a158f3d556d0d934 *man/env_poke.Rd -7d30ffcdbe51324da7ed5970cd5bb79c *man/env_print.Rd -3e621a22835927c898619a644b083640 *man/env_unbind.Rd +69608a9d734c63d716efeded8d33d1f9 *man/env_print.Rd +0cf194f1ec3a0a96ef943d1297ad01e1 *man/env_unbind.Rd 51cae32ed1f181fee83f694d37a8baf6 *man/env_unlock.Rd a78184e9d096bdffd0263dd117e96294 *man/eval_bare.Rd -aa07977f472c9df92fdf5f6af04ec743 *man/eval_tidy.Rd +4b251892cbfcda657304abbb9697cf17 *man/eval_tidy.Rd cd22ab89004120aec8e2dad3b65a4b02 *man/exec.Rd 22dc0fba69f406cb106a2d026a87d744 *man/exiting.Rd 90df05f7445387c6d0a0a5f2a99c7678 *man/expr_interp.Rd @@ -150,13 +157,15 @@ da6985c05634ac13d265f277265f6dc1 *man/fn_body.Rd fb6a9867bff132541ea3830d5707ad29 *man/fn_env.Rd 6ed6c420ba258116d089292e292196fb *man/fn_fmls.Rd -b74e0e52be647dbc34557875d517a605 *man/format_error_bullets.Rd +27cc2f2c5a12960ff4dcb4ddb614607f *man/format_error_bullets.Rd bebd7f75a2c8bbf9aa62187604f507e0 *man/frame_position.Rd 173e5384356e2384b1785e2e3892f0b1 *man/friendly_type.Rd a8ae08d2e73e467d60b7ab71255ad1e2 *man/get_env.Rd 36a034671a550aae53290d36e926ddc7 *man/has_length.Rd 9314263b645e88284694fffcb74117c8 *man/has_name.Rd +86523fa27213ad1f2a038e1ce2a9b70c *man/hash.Rd 2f013cc6446d059609819be4fb2a3777 *man/inherits_any.Rd +86317bb3faa6dccd7af3cb7305a5ba37 *man/inject.Rd 6de3c9de434c72fd5e2bbd28183d9018 *man/invoke.Rd a6fd832b4a4f7de63547ed811e8563b4 *man/is_call.Rd 7a153c5c18079918623d0b5a9ed89284 *man/is_callable.Rd @@ -170,7 +179,7 @@ f1151d26fb8190d83e147f1cd9e1cc66 *man/is_formula.Rd 593cb5564a4df84f56583d2826f7bc72 *man/is_frame.Rd 78d8661d0445585e5927839570b38a70 *man/is_function.Rd -d37cc51a437f8a6930040137c5a4f6fe *man/is_installed.Rd +5d72a15d3507f614364fe41f6fa7796e *man/is_installed.Rd e1e67bbed234e93c04bac1fb45b17019 *man/is_integerish.Rd 64428493e2062ee4394c9a644fa04ee7 *man/is_interactive.Rd 5170a8d21b9d587a244c5c80217a9610 *man/is_lang.Rd @@ -203,7 +212,7 @@ 73f43de162110988a7b3839b2f2bcffc *man/new_quosures.Rd 124c3a599323e8c3eeb8eedaa5c49594 *man/new_weakref.Rd d23b90fcc6c8bc8579e9a3817408476b *man/ns_env.Rd -2a49f935f3bc6fd4a0ac93b84d7f58fc *man/nse-defuse.Rd +93ae5f37c32cff3191a8fd5b7f3b6a35 *man/nse-defuse.Rd 1da86d98a2f3296e0efa0f1cd5252c36 *man/nse-force.Rd e1462d9d9630b4d9512d18d12b36b496 *man/op-definition.Rd 84259297bc000baf9e9d182954fd6653 *man/op-get-attr.Rd @@ -211,9 +220,8 @@ 104a6a1976e8c95b00c7f5f3457ba6d7 *man/op-null-default.Rd 107df637d90fda4f84a41437b504610d *man/overscope_eval_next.Rd efff9235671da7b9fe38b1f992b9018f *man/pairlist2.Rd -8e7473f0b48c64e17aca099fa10b5381 *man/parse_expr.Rd -f6dc8062a28ceb49dd9635faec626318 *man/parse_quo.Rd -cce790417efbd72dd978eec51da20690 *man/parse_quosure.Rd +6814eb0c4a04dcb948900e5aee370aac *man/parse_expr.Rd +d1cf4de342830dec921ae5df53df081b *man/parse_quosure.Rd 658cfff90cff0be2d3276618e0afb786 *man/prepend.Rd afc9cc159795e4415c38a5987075910d *man/prim_name.Rd 1b5abc0211ff2b8e9187b65f8fc072de *man/quo_expr.Rd @@ -230,7 +238,7 @@ 244d1cbe6864e1e25887a1392b9f89f0 *man/scalar-type-predicates.Rd 04fd2d4a4cd6700b476ba24c07e21d30 *man/scoped_env.Rd cccf9ad2f317740ee8e1448fcbacf35c *man/scoped_interactive.Rd -244a592b475da54c4fa3a3037da673d7 *man/search_envs.Rd +7d1173fbd423e97d0d15512dcbdf29df *man/search_envs.Rd 231f1a6e76b2d308aa1eb9c6430e3bcb *man/seq2.Rd 62f12ec1e10346ae91840aad410731f0 *man/set_attrs.Rd 34595dfb7e8fefad12dd8d6a0ae4ec62 *man/set_expr.Rd @@ -241,7 +249,7 @@ b69de2a056ee5d0160066f8189a32546 *man/string.Rd 8939306087c5e73f23df8810100df086 *man/switch_type.Rd cedb35b0b50689b6a9710aeafbaa6e31 *man/sym.Rd -64e147716a7a049c97f98d661475a5ce *man/tidyeval-data.Rd +bb4b65156f70d370824ea47b150b05a6 *man/tidyeval-data.Rd 093365b5b5a08f8ebd77adc9d31d509b *man/trace_back.Rd eca9ef0935bd42d1afee5bd0b47396d8 *man/type-predicates.Rd cc36b3b4ffbd397b87f20075ad4d6ad5 *man/type_of.Rd @@ -255,40 +263,45 @@ b1204f0748c1c2665bc9870d228aec4d *man/with_restarts.Rd 6dadd42c4837cfdd7bd7c647a875f065 *man/wref_key.Rd b1488158ec99011b492963e9bcae0a8b *man/zap.Rd -6586c16256cf85e49567f800790c2eeb *src/Makevars -10ee83abd769da3bb96ec811de18c886 *src/capture.c +5f844153c5118bd3171727127790d78c *man/zap_srcref.Rd +75ad6155baad536069ad1b597b3da7bf *src/Makevars +02b9d2813f940ee18e841aca9b4692f1 *src/capture.c 4ef367588c5e607b1a99842eba7d6a5f *src/config.h 372738f63854b1faa1e7dc2c3768a7b0 *src/export.c b4b080a14585a97b3e9c1cf20ca9febd *src/export/exported-tests.c -744be8bc49fc3f0590702e4b706a38c3 *src/export/exported.c -b49eaa1cde4f6ad93024a8b81e8fd8a7 *src/export/init.c -a715e0abe4b42c0209dd8c4b22bef7a1 *src/internal.c -c5ba49033a43b3fef787e350a9cd9a74 *src/internal/arg.c +e984bbe8f21ebc4dd2aaab9c7dd89f36 *src/export/exported.c +40e8093e008d30bb6de5078e1fe651d8 *src/export/init.c +1cd9bbf1c3167e7d03caf44a5187b61e *src/internal.c +35b33de6cb14206931827bf51a2001aa *src/internal/arg.c d539e86ca61e2216a17fcf8fb70dea95 *src/internal/attr.c 665a7a36d9331c914fa0abe3bb451792 *src/internal/call.c -155262f5e9e2faea379a091ff423ca5c *src/internal/dots.c +071a918df45b6f595aafe16d37f6923f *src/internal/dots.c 3f13fd0791f56ee38ecdd013b0312ddb *src/internal/dots.h -6009022fc67d21ea055b621fea98b01f *src/internal/env-binding.c +0a19784fe566464df8f670a1f8f1925f *src/internal/env-binding.c 89d1c417dfdf35daf96afd2f105bfa9e *src/internal/env.c -e48fbc11c60d2603cdbd35a20c95b31d *src/internal/eval-tidy.c +59422314dbd66f1098987f9a9bea7be3 *src/internal/eval-tidy.c d05ba3f2d2584fdd5f7c2098ec219e03 *src/internal/eval.c 8a6b0be53d8af9798bb55690616b2f81 *src/internal/expr-interp-rotate.c d94334212a74d3d56e347d85675e5ea5 *src/internal/expr-interp-rotate.h ac891cd3509127a60184cc5de048988f *src/internal/expr-interp.c 5987fd35349209dcf117087ef83833a2 *src/internal/expr-interp.h 8637d965924f4c9e8a55298733efb534 *src/internal/fn.c +dbe01688e88c6edf234dbb29747b5cc2 *src/internal/hash.c a565685a253f6b05df113c9294715325 *src/internal/internal.c 9b1ae81631f4e551e67909ae3c449f62 *src/internal/internal.h +a1d97ad193ea39845428e95f5f0f0001 *src/internal/nse-defuse.c 3974242354b693eb707181e3a8454cd1 *src/internal/quo.c eede28d66f0412d290e3b00fe17745b1 *src/internal/quo.h -2bb7d72c87f1aa1fd3f1d93f822e25d0 *src/internal/utils.c -ae79abafc1e13d2fc28e1cb8b2101148 *src/internal/utils.h +0cd9b35226c18b792cda1fa82daf1e5d *src/internal/utils.c +3ec17d042bf3482eebbfab367b42bbe2 *src/internal/utils.h 5016c8de37928f8da9408c2d4d42d6b1 *src/internal/vec-raw.c +3066518b768e229d4b44248362581f9c *src/internal/xxhash/xxhash.h a76b4649b52f32c495a82071da3e8adc *src/lib.c 9e0f95b073d7cbb6c5ed95f03533320b *src/lib/attrs.c 8b6e8dfe2da62a18dcfa7c0ccd046e7c *src/lib/attrs.h +dd3694c9aab861776bd56fef094b798e *src/lib/c-utils.h 0885ced67199979ea7ae56827beb0699 *src/lib/cnd.c -8899873352e24af983fc925532358ee4 *src/lib/cnd.h +3d000213ddfc20a05e665cfc94f85039 *src/lib/cnd.h f0e4853e04c64df801a9fca243efefaa *src/lib/debug.c 222e85a41a1d02518c1f7409153dc714 *src/lib/debug.h a40ed6fb8335b798c3c2b5e3680fa09c *src/lib/env-binding.c @@ -307,14 +320,14 @@ 6beb48b277b89161d9783861df1f768e *src/lib/lang.h d51219cd88ae2c5bcfd98dd8c0ea1d91 *src/lib/node.c 37a53c3c2fd0f63b4d6239e3f95e7302 *src/lib/node.h -ab930f0279639637a7903ae84fe15d81 *src/lib/parse.c -07ff98ca6ec48ddd488d31b4108a7aa0 *src/lib/parse.h +a887e68970f44102453051231d748429 *src/lib/parse.c +e8d21929cd63ccb42218445691dd5123 *src/lib/parse.h bfd369311f1b014af975e8d169090b42 *src/lib/quo.c b1395da0d9a1a6e1a0e8b96f8d122af4 *src/lib/quo.h 51f83072d799b8da4cedf5ae0c3de75b *src/lib/replace-na.c c8ad3bada9f5789697a13b0e0489f953 *src/lib/replace-na.h -a4b7e33890461993c1c99e3dcaae488e *src/lib/rlang.c -84ea6a577c3e90a2a77406d9d8359ffe *src/lib/rlang.h +c772dc9c113292a152215bae758f4aeb *src/lib/rlang.c +010aeeb1a71ff70149d6818d0310d0f2 *src/lib/rlang.h 634a6c9ebb0ed74ab8e0ee8efe1f0caf *src/lib/session.c ec7812f53895289341237370654f38f3 *src/lib/session.h 7ce86191af123f9fd1a3daeff5122139 *src/lib/sexp.c @@ -336,9 +349,17 @@ 0572d3ac35ad5e229d891d2d10218b33 *src/lib/vec.c 0355c8d2b71d4a0b3cff2ef7e0015140 *src/lib/vec.h f62bfc377df0fd1681959ba55ea4d5a6 *src/lib/weakref.c -e84cad1d8f9bcd5da3bbd652034dcb0d *src/version.c -f35548b4703093ff446d08cc838abb4e *tests/sink.R +04945de99d61197a2ab6333e46047a9b *src/version.c +b535466226f2ed8212a97ea8790639c4 *tests/sink.R 689f0fa1b25df0719206586844edb2d0 *tests/testthat.R +3297ab75ebf197b920885af68a5767b6 *tests/testthat/_snaps/arg.md +e49b84e32d2a6ce238aa983f0bff66bc *tests/testthat/_snaps/cnd-abort.md +0b2795e24911a1b6842ec6fc32602ff9 *tests/testthat/_snaps/cnd-entrace.md +363538efbe6cdc931e9f511e9ca21095 *tests/testthat/_snaps/cnd-error.md +33fa589d4445941c4c6631c6b0be7eaa *tests/testthat/_snaps/cnd-signal.md +38d02a8e9faa2b8ffa88f7059fdaa83d *tests/testthat/_snaps/env-special.md +8ab00b9a4b0fa9641b61c2c1ca06ba87 *tests/testthat/_snaps/operators.md +d5a4960bff2ed4098570ffd5642818d7 *tests/testthat/_snaps/trace.md ba141ebe66e9cbf68456c4894d8f811d *tests/testthat/fixtures/Makefile 2759ff4c56f377e704ba0b25c325b13c *tests/testthat/fixtures/error-backtrace-conditionMessage.R ac9346885a36276a5ecc31dd63ea2dfe *tests/testthat/fixtures/error-backtrace-empty.R @@ -354,116 +375,64 @@ b2a1450e0cec785c0feed66d31219788 *tests/testthat/fixtures/rlanglibtest/src/init.c 7295d46696a4d41f92a5f967c65edf5a *tests/testthat/fixtures/rlanglibtest/src/test-quo-accessors.c d18d1bdcf3564ccaa3a32da5977d5787 *tests/testthat/fixtures/rlanglibtest/tests/testthat.R -cf4af2dc60c747068c60d6504d34e8a8 *tests/testthat/fixtures/rlanglibtest/tests/testthat/test-quo-accessors.R +0265f256d07760e01cf9754ccba69504 *tests/testthat/fixtures/rlanglibtest/tests/testthat/test-quo-accessors.R 14b5a0404c1240c2cab8fe47085c7edb *tests/testthat/fixtures/trace-srcref.R 76a8ca39c3610fd42d7cb362977467b0 *tests/testthat/helper-c-api.R ecbf0c40449bcf70ea203788c4e27cac *tests/testthat/helper-capture.R -3b482bee49095e2920cddd0b1d03672f *tests/testthat/helper-cli.R -71a741f89e168366b2cae6b75a2149e8 *tests/testthat/helper-cnd.R -2d7ee799c99c893d163355e80c164ed0 *tests/testthat/helper-locale.R -b5e36a405464386132f17ffe709c2c1a *tests/testthat/helper-output.R +7e8e22ccf10aac343d591547d1da9a81 *tests/testthat/helper-cli.R +b513233e92963ef2b65211c5c55e3a1c *tests/testthat/helper-cnd.R +1784993bee6185448d9aa227e4907dd8 *tests/testthat/helper-locale.R 71d70b5fc2aa426a2918ec167f657855 *tests/testthat/helper-print.R -c16b053e407d860a1d1f1d6c9a2b8fa1 *tests/testthat/helper-rlang.R +7c5f76aced2beac366c64851dbc8c774 *tests/testthat/helper-rlang.R a20ff5a7133d7e0407ccd1ea4ff6034e *tests/testthat/helper-stack.R -6098121d6f5bf36b8d9385369a2e4a02 *tests/testthat/helper-trace.R -b0b7116975f44ca093da2251b12fee35 *tests/testthat/output-cnd-abort-parent-trace.txt -afa2a125a13cc5b8175c149c26b9d114 *tests/testthat/output-cnd-abort-trace-reminder.txt +9e1e14e8ae677e073adb0dd9f53818b5 *tests/testthat/helper-trace.R 174be906c15a7e0857eeb05b32a1bcb0 *tests/testthat/setup-tests.R 512dd39b4a02489cc9cbc68c76480b3d *tests/testthat/teardown-tests.R -25edfe3a49854b7da2a10ded17f49d1d *tests/testthat/test-arg.R -0045374e815c6534a4b467323b8e1a82 *tests/testthat/test-attr.R -91298fb49fb3d9b3e21f430648767814 *tests/testthat/test-c-api.R -556347b51ae8ecd6d88052400ec22e55 *tests/testthat/test-call.R -a9eb26ba5adbd766457c38b651335fbb *tests/testthat/test-cnd-abort.R -16ed50878917f1bbeca75a5e82992fab *tests/testthat/test-cnd-entrace.R -a7350bc25732b7fa01be5a41a0e19f2f *tests/testthat/test-cnd-error-conditionMessage.txt -30feb0f485e9e70f1b0e45973e76317a *tests/testthat/test-cnd-error-empty.txt -010115bb88c8ec81a23e13dcfaa8dea4 *tests/testthat/test-cnd-error-parent-default.txt -42e42a43130394c6334e51a73aaa08e3 *tests/testthat/test-cnd-error-parent-full.txt -67cb11e09cb6efe8c320cac2ea773482 *tests/testthat/test-cnd-error-parent-trace.txt -e533d69ca78aabd8b057792a0ef5825c *tests/testthat/test-cnd-error-parent.txt -d79369627b1fe56c6160502102ab471b *tests/testthat/test-cnd-error-print-base-parent.txt -814aa456670852335d566a02711a76c9 *tests/testthat/test-cnd-error-print-no-message.txt -33a47e7994726ca9a997bf8dac1cbc8b *tests/testthat/test-cnd-error-str.txt -3e226cf897bbe1bfbfb9dd02835fc920 *tests/testthat/test-cnd-error.R -0e779950fa09fa9d6dc7affc698149c5 *tests/testthat/test-cnd-error.txt -f4393c3e96eb053c347f6722e08607ae *tests/testthat/test-cnd-handlers.R -cec5a718ab698eda965a7777cc5a4e43 *tests/testthat/test-cnd-message.R -157803aa1cb3e646b56e3a7a93f9db7f *tests/testthat/test-cnd-signal-trace.txt -bb6ea7823c2b4e6f1a33a681834e4435 *tests/testthat/test-cnd-signal.R -e28f232aeaa0e9f129cc42f243208708 *tests/testthat/test-cnd.R -7df45679d1c8565b82a09b385506d148 *tests/testthat/test-compat.R -341ddf55904d2fb7b54aa71409da099b *tests/testthat/test-deparse.R -316bc706f8a03696495da80fb992b261 *tests/testthat/test-dots.R -441d927b3b0e857c429652c3840e4e8d *tests/testthat/test-encoding.R -ac23677a062d1f3e807664a0ec8d6cbd *tests/testthat/test-entrace.txt -7d270024967d4b1e67f35ab2376f17d8 *tests/testthat/test-env-binding.R -6fb58a3b2394e26515479a9abd470b18 *tests/testthat/test-env-special.R -5672ece85d4a4b678f9e9989f99d33f5 *tests/testthat/test-env.R -a969f70060db560530fa0eacfda9f791 *tests/testthat/test-error-print-conditionMessage.txt -54b0eeb66676068b086b6a2379623a66 *tests/testthat/test-eval-tidy.R -f4c54250bdd6f738a8345062898beeaf *tests/testthat/test-exec.R -fc481fb91e65da643e012883f3c2cddf *tests/testthat/test-expr.R -fbdd0ca212fc02908ff41bcabc0e0eca *tests/testthat/test-fn.R -1bc98da29fef967ac23d58c02a076bec *tests/testthat/test-formula.R -33560dafbd5f796f2423bdb9079787a4 *tests/testthat/test-lifecycle.R -144d6e49fcde43909d489a88ec903a78 *tests/testthat/test-node.R -a3515d2e5e7c75e93c7094eb168968ca *tests/testthat/test-nse-defuse.R -2a3fb99adb8c075b0767b681297a643f *tests/testthat/test-nse-force.R -fa414041373218367a6bf79b1797c52e *tests/testthat/test-operators-replace-na.txt -a02a4815c9decf986ca015bbf846f44b *tests/testthat/test-operators.R -1ecde6152910219d29b1c2f40f61ac47 *tests/testthat/test-parse.R -3c9dc83d5303a101721234be13a121eb *tests/testthat/test-quo.R +40e5040ec43155253d572603302685c7 *tests/testthat/test-arg.R +bcd2d4c2bc5a2e0a5eee56c14a3b9ef2 *tests/testthat/test-attr.R +d8c23d5bc975fb3ed3937e4e5e6ce45a *tests/testthat/test-c-api.R +d31b82b7f29fce027982ef4780f5f0ed *tests/testthat/test-call.R +69a8df287375b2b2f04c466eed608961 *tests/testthat/test-cnd-abort.R +05472c0dc8ee60198795a3b4f3a42247 *tests/testthat/test-cnd-entrace.R +af25012d37805bcad20d765b808d43cb *tests/testthat/test-cnd-error.R +e806c4ce6359071990d91656f535c76a *tests/testthat/test-cnd-handlers.R +d6016515dca168b3359620391b44f3be *tests/testthat/test-cnd-message.R +acdb35aa599693dace0ef6a1a115c093 *tests/testthat/test-cnd-signal.R +57f3f3ebcd9bf08ffd71de4e6a24f967 *tests/testthat/test-cnd.R +118fdca850c936ea6594cb4d5dcb3ba3 *tests/testthat/test-compat-zeallot.R +0a55d24ab0a36e048f4ae92751d27294 *tests/testthat/test-compat.R +613524b562b490611cef576c01da1136 *tests/testthat/test-deparse.R +a40b600e622389bf823dcfb3a842c0aa *tests/testthat/test-dots.R +d5338aaed8433357012a7d3523919d4c *tests/testthat/test-encoding.R +071be7fdbaf9d9dd383bbddb36d011ed *tests/testthat/test-env-binding.R +c078bcef8bbcad174edb329b06f9bc7e *tests/testthat/test-env-special.R +abb6715f6afdedbfd421cca896c3c800 *tests/testthat/test-env.R +9871e158ad656a85e2cf44b740e10bbf *tests/testthat/test-eval-tidy.R +377cd0001f2ba46fc77a93b4b06733ef *tests/testthat/test-eval.R +9bdab2e6fa6b2b1455e4f4f856a1b7ba *tests/testthat/test-expr.R +e7b21cff1081a48e25fb64d83881f22d *tests/testthat/test-fn.R +814942b62e15b3843f551b9193d8a701 *tests/testthat/test-formula.R +422f16f0698c9309fabd1ace0ce45f24 *tests/testthat/test-hash.R +e96ea9c64b1430397ab066f15b4e4220 *tests/testthat/test-lifecycle.R +f581e7bb8b471157139bdb84e0f392ae *tests/testthat/test-node.R +6f10862288a29039baa4a9ddd36afe29 *tests/testthat/test-nse-defuse.R +369c5d7ba60165f89f5b19e6297ec741 *tests/testthat/test-nse-force.R +013bf4e8505d674a99d620271e861d78 *tests/testthat/test-operators.R +bb4e778340942684b87aaebffd40203d *tests/testthat/test-parse.R +ef5becd3676a15e63c565cbe4257b6c9 *tests/testthat/test-quo.R 9b5fcad3895f42f389b18c755e9d4dd1 *tests/testthat/test-raw.R -ea8d58b90449981343e888bf97b5ee55 *tests/testthat/test-retired.R -12c61b61febb98ecca2b4d80316c813a *tests/testthat/test-s3.R -cde921e0059c385b8022c9b31a257a59 *tests/testthat/test-sexp.R -6ee94643e23e5c19dd96e2da620467c8 *tests/testthat/test-stack.R -77dc128c01517162e5127213fd68d34d *tests/testthat/test-state.R -fe0d60f8c170f6579a036e4d2edf18b8 *tests/testthat/test-sym.R -9df2edf93f43b86ef67748f218ac906c *tests/testthat/test-trace-backtrace-anonymous.txt -16160422020d641a7ed2aab5ce557950 *tests/testthat/test-trace-backtrace-branch-first-frame.txt -60493aadab991fc90663d6122cb3f4b5 *tests/testthat/test-trace-call-car-promise.txt -cc5c0935bd172edd785a52250385caa8 *tests/testthat/test-trace-collapse-children.txt -e4d446e136aecdf87164cc91e5472096 *tests/testthat/test-trace-collapse-eval.txt -2515ae22f00d1e062f5dd1922270d8fb *tests/testthat/test-trace-collapse-evalq.txt -591183217907067d66729bc3994f875e *tests/testthat/test-trace-collapse-magrittr-before-after1.txt -e13f9f6db2760c7a4a839846cffb122e *tests/testthat/test-trace-collapse-magrittr-before-after2.txt -30c67df57fc8fbac4300ddc8e104847c *tests/testthat/test-trace-collapse-magrittr-before-after3.txt -ffa03cf5f4f451a55dc3405ab7a8b7c9 *tests/testthat/test-trace-collapse-magrittr-children.txt -128cbf7087da80e7619f8ca5b26a6215 *tests/testthat/test-trace-collapse-magrittr-complete-leading1.txt -eef6075f8ab731380aff40a5f4f8b736 *tests/testthat/test-trace-collapse-magrittr-complete-leading2.txt -f8a95ab1a166e90fd5b4c4032aebf69d *tests/testthat/test-trace-collapse-magrittr-complete1.txt -97eb68753e05d19ef1b7272565c8acf6 *tests/testthat/test-trace-collapse-magrittr-complete2.txt -0d6bd71f0e2557ee656eb28a535e1b83 *tests/testthat/test-trace-collapse-magrittr-incomplete-leading1.txt -fa413c01705388f46b32cbc3c540a220 *tests/testthat/test-trace-collapse-magrittr-incomplete-leading2.txt -3f7153543c90a10759b67d7dae76bc1f *tests/testthat/test-trace-collapse-magrittr-incomplete.txt -3b35fa4015f51f7820052067a2ad1d41 *tests/testthat/test-trace-collapse-magrittr.txt -8b510a0ae422c03f57082782be650462 *tests/testthat/test-trace-collapse-magrittr2.txt -1442a736ddeb690bd95322efa4ea2603 *tests/testthat/test-trace-collapse-magrittr3.txt -cd374f0b8f022676580e4822d2e2d57b *tests/testthat/test-trace-collapsed1.txt -e14846276522724110365f2942657d81 *tests/testthat/test-trace-collapsed2.txt -737305c359e5a2dc156a06d13e598895 *tests/testthat/test-trace-dangling-srcref.txt -d75f1a8c5a7f6fec60e5128f0d986c95 *tests/testthat/test-trace-degenerate-null.txt -ee101590748d8a60d132c87c33f51051 *tests/testthat/test-trace-degenerate-scalar.txt -1d004ad36b020b70fa5da2697f6508b3 *tests/testthat/test-trace-degenerate-sym.txt -0f8f920358b91fea42a830936639df9a *tests/testthat/test-trace-global-prefix.txt -b7171d84dcf0e1c9b0578b67f13795f9 *tests/testthat/test-trace-local-prefix.txt -7c68acccbcfc50fa04ec8337704111a3 *tests/testthat/test-trace-non-collapsed-eval -49e01699ca0f6893e2ed07de34a4ee96 *tests/testthat/test-trace-print.txt -2149b6f3d4f118c8c2c99e9929a02107 *tests/testthat/test-trace-recursive.txt -ffc6a7a756e17da1c97b153a623ada0d *tests/testthat/test-trace-summary.txt -14d26652d1ea3ece060ff1e2629459c8 *tests/testthat/test-trace-trim.txt -29b9bccd977f39167ee060b79363d70d *tests/testthat/test-trace-truncate-backtrace-branch.txt -d10f376dad7ac53cbd2442a1cc5d8b6f *tests/testthat/test-trace-unexported-prefix.txt -4da05492c4283efedd386a3e3432f347 *tests/testthat/test-trace.R +f92a959428f6a9c7f5376ffb8fa00b0a *tests/testthat/test-retired.R +cd79a31ecfc1258251c3949b62a4578f *tests/testthat/test-s3.R +b6b164362e05305015b0062f0049fa84 *tests/testthat/test-sexp.R +ddb5935397104cb873081cac47806e11 *tests/testthat/test-stack.R +80c9eead55f02ad72447293de69cb824 *tests/testthat/test-state.R +68299e069d76862a792bb1e75dd08f3e *tests/testthat/test-sym.R +5d0939e5c546ddfde9f9468bb297d6c1 *tests/testthat/test-trace.R 6b1b3510ea7e63829803b8c61fa82162 *tests/testthat/test-trace.Rmd -9c774a68f57dfb29ab48970f226d0ff8 *tests/testthat/test-types.R -f377b9705063cdcfd3c5791a2cfab7f4 *tests/testthat/test-typo-suggest.txt -398137d343f4a18ad98464064f5364fa *tests/testthat/test-utils.R -8645364b987e2c1d7aa2a1986412abb3 *tests/testthat/test-vec-new.R -a9c6c389d7adce09814ffa9b097eb3d8 *tests/testthat/test-vec-squash.R -b69c4a48b28aa8c81649819a4915bd51 *tests/testthat/test-vec-utils.R -fd2507820f81ffc5549ff8be3e1ce1ac *tests/testthat/test-vec.R -fdef13a19485fd841541309b570cb824 *tests/testthat/test-weakref.R -04a7bb4ca3619dcb6af99f37e4f0120e *tests/testthat/test-with-abort.txt +7e524f39a32e0f56417ecd2257343b52 *tests/testthat/test-types.R +3832446ded2e55090d914d8d393feb62 *tests/testthat/test-utils.R +fcbf18c3edc78c2b4a83015ea0335955 *tests/testthat/test-vec-new.R +9afb180c402a1a71ad58c9340a989212 *tests/testthat/test-vec-squash.R +c53fedcc096fc0e78885803eb08203e2 *tests/testthat/test-vec-utils.R +6d598358360c2826d184bb9307ccd94c *tests/testthat/test-vec.R +4a1728873bd8bc0a97a4d9109655a1ae *tests/testthat/test-weakref.R diff -Nru r-cran-rlang-0.4.8/NAMESPACE r-cran-rlang-0.4.10/NAMESPACE --- r-cran-rlang-0.4.8/NAMESPACE 2020-10-07 09:12:19.000000000 +0000 +++ r-cran-rlang-0.4.10/NAMESPACE 2020-12-18 09:31:10.000000000 +0000 @@ -67,6 +67,7 @@ S3method(summary,rlang_trace) export("!!!") export("!!") +export("%<~%") export("%@%") export("%@%<-") export("%|%") @@ -132,6 +133,7 @@ export(caller_frame) export(calling) export(catch_cnd) +export(check_installed) export(child_env) export(chr) export(chr_along) @@ -171,7 +173,9 @@ export(enexpr) export(enexprs) export(enquo) +export(enquo0) export(enquos) +export(enquos0) export(ensym) export(ensyms) export(entrace) @@ -186,6 +190,7 @@ export(env_binding_are_locked) export(env_binding_lock) export(env_binding_unlock) +export(env_browse) export(env_bury) export(env_clone) export(env_depth) @@ -193,6 +198,7 @@ export(env_get_list) export(env_has) export(env_inherits) +export(env_is_browsed) export(env_is_locked) export(env_label) export(env_length) @@ -249,11 +255,13 @@ export(global_frame) export(has_length) export(has_name) +export(hash) export(have_name) export(inform) export(inherits_all) export(inherits_any) export(inherits_only) +export(inject) export(int) export(int_along) export(int_len) @@ -534,6 +542,7 @@ export(wref_key) export(wref_value) export(zap) +export(zap_srcref) importFrom(stats,median) importFrom(stats,quantile) importFrom(utils,adist) diff -Nru r-cran-rlang-0.4.8/NEWS.md r-cran-rlang-0.4.10/NEWS.md --- r-cran-rlang-0.4.8/NEWS.md 2020-10-07 10:44:44.000000000 +0000 +++ r-cran-rlang-0.4.10/NEWS.md 2020-12-18 09:31:26.000000000 +0000 @@ -1,3 +1,90 @@ +# rlang 0.4.10 + +* New `hash()` function to generate 128-bit hashes for arbitrary R objects + using the xxHash library. The implementation is modeled after + [xxhashlite](https://github.com/coolbutuseless/xxhashlite), created + by @coolbutuseless. + +* New `check_installed()` function. Unlike `is_installed()`, it asks + the user whether to install missing packages. If the user accepts, + the packages are installed with `pak::pkg_install()` if available, + or `utils::install.packages()` otherwise. If the session is non + interactive or if the user chooses not to install the packages, the + current evaluation is aborted (#1075). + +* rlang is now licensed as MIT (#1063). + +* Fixed an issue causing extra empty lines in `inform()` messages with + `.frequency` (#1076, @schloerke). + +* `expr_deparse()` now correctly wraps code using `::` and `:::` + (#1072, @krlmlr). + + +# rlang 0.4.9 + +## Breaking changes + +* Dropped support for the R 3.2 series. + + +## New features + +* `inject()` evaluates its argument with `!!`, `!!!`, and `{{` + support. + +* New `enquo0()` and `enquos0()` operators for defusing function + arguments without automatic injection (unquotation). + +* `format_error_bullets()` is no longer experimental. The `message` + arguments of `abort()`, `warn()`, and `inform()` are automatically + passed to that function to make it easy to create messages with + regular, info, and error bullets. See `?format_error_bullets` for + more information. + +* New `zap_srcref()` function to recursively remove source references + from functions and calls. + +* A new compat file for the zeallot operator `%<-%` is now available + in the rlang repository. + +* New `%<~%` operator to define a variable lazily. + +* New `env_browse()` and `env_is_browsed()` functions. `env_browse()` + is equivalent to evaluating `browser()` within an environment. It + sets the environment to be persistently browsable (or unsets it if + `value = FALSE` is supplied). + +* Functions created from quosures with `as_function()` now print in a + more user friendly way. + +* New `rlang_print_backtrace` C callable for debugging from C + interpreters (#1059). + + +## Bugfixes and improvements + +* The `.data` pronoun no longer skips functions (#1061). This solves a + dplyr issue involving rowwise data frames and list-columns of + functions (tidyverse/dplyr#5608). + +* `as_data_mask()` now intialises environments of the correct size to + improve efficiency (#1048). + +* `eval_bare()`, `eval_tidy()` (#961), and `with_handlers()` (#518) + now propagate visibility. + +* `cnd_signal()` now ignores `NULL` inputs. + +* Fixed bug that prevented splicing a named empty vector with the + `!!!` operator (#1045). + +* The exit status of is now preserved in non-interactive sessions when + `entrace()` is used as an `options(error = )` handler (#1052, + rstudio/bookdown#920). + +* `next` and `break` are now properly deparsed as nullary operators. + # rlang 0.4.8 diff -Nru r-cran-rlang-0.4.8/R/aaa.R r-cran-rlang-0.4.10/R/aaa.R --- r-cran-rlang-0.4.8/R/aaa.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/R/aaa.R 2020-12-18 09:00:51.000000000 +0000 @@ -0,0 +1,16 @@ + +on_load <- function(expr, env = topenv(parent.frame())) { + callback <- function() eval_bare(expr, env) + env$.__rlang_hook__. <- c(env$.__rlang_hook__., list(callback)) +} + +run_on_load <- function(env = topenv(caller_env())) { + hook <- env$.__rlang_hook__. + env_unbind(env, ".__rlang_hook__.") + + for (callback in hook) { + callback() + } + + env$.__rlang_hook__. <- NULL +} diff -Nru r-cran-rlang-0.4.8/R/arg.R r-cran-rlang-0.4.10/R/arg.R --- r-cran-rlang-0.4.8/R/arg.R 2020-07-09 12:32:41.000000000 +0000 +++ r-cran-rlang-0.4.10/R/arg.R 2020-11-19 12:47:54.000000000 +0000 @@ -241,7 +241,7 @@ #' @rdname missing_arg #' @export is_missing <- function(x) { - .External2(rlang_ext2_is_missing, missing(x)) + missing(x) || is_reference(x, quote(expr = )) } #' @rdname missing_arg diff -Nru r-cran-rlang-0.4.8/R/attr.R r-cran-rlang-0.4.10/R/attr.R --- r-cran-rlang-0.4.8/R/attr.R 2020-08-12 08:53:53.000000000 +0000 +++ r-cran-rlang-0.4.10/R/attr.R 2020-12-18 09:00:51.000000000 +0000 @@ -243,3 +243,54 @@ poke_attributes <- function(x, attrs) { .Call(rlang_poke_attrib, x, attrs) } + +#' Zap source references +#' +#' @description +#' +#' There are a number of situations where R creates source references: +#' +#' - Reading R code from a file with `source()` and `parse()` might save +#' source references inside calls to `function` and `{`. +#' - [sys.call()] includes a source reference if possible. +#' - Creating a closure stores the source reference from the call to +#' `function`, if any. +#' +#' These source references take up space and might cause a number of +#' issues. `zap_srcref()` recursively walks through expressions and +#' functions to remove all source references. +#' +#' @param x An R object. Functions and calls are walked recursively. +#' +#' @export +zap_srcref <- function(x) { + if (is_closure(x)) { + body(x) <- zap_srcref(body(x)) + return(x) + } + if (!is_call(x)) { + return(x) + } + + x <- duplicate(x, shallow = TRUE) + + if (!is_null(sexp_attrib(x))) { + attr(x, "srcref") <- NULL + attr(x, "wholeSrcref") <- NULL + attr(x, "srcfile") <- NULL + } + if (is_call(x, "function")) { + node <- node_get(x, 3) + if (!is_null(node)) { + node_poke_cdr(node, NULL) + } + } + + node <- x + while (!is_null(node)) { + node_poke_car(node, zap_srcref(node_car(node))) + node <- node_cdr(node) + } + + x +} diff -Nru r-cran-rlang-0.4.8/R/call.R r-cran-rlang-0.4.10/R/call.R --- r-cran-rlang-0.4.8/R/call.R 2020-07-09 12:32:41.000000000 +0000 +++ r-cran-rlang-0.4.10/R/call.R 2020-11-20 09:59:23.000000000 +0000 @@ -273,7 +273,7 @@ unmatched <- TRUE for (elt in name) { - if (identical(x[[1]], sym(elt))) { + if (identical(node_car(x), sym(elt))) { unmatched <- FALSE break } diff -Nru r-cran-rlang-0.4.8/R/cnd-abort.R r-cran-rlang-0.4.10/R/cnd-abort.R --- r-cran-rlang-0.4.8/R/cnd-abort.R 2020-07-30 12:38:45.000000000 +0000 +++ r-cran-rlang-0.4.10/R/cnd-abort.R 2020-11-20 15:57:08.000000000 +0000 @@ -50,12 +50,18 @@ #' guaranteed. #' #' @inheritParams cnd -#' @param message The message to display. -#' -#' If not supplied, it is expected that the message is generated -#' lazily through [conditionMessage()][cnd_message]. In that case, -#' `class` must be supplied. Only `inform()` allows empty messages -#' as it is occasionally useful to build user output incrementally. +#' @param message The message to display. Character vectors are +#' formatted with [format_error_bullets()]. The first element +#' defines a message header and the rest of the vector defines +#' bullets. Bullets named `i` and `x` define info and error bullets +#' respectively, with special Unicode and colour formatting applied +#' if possible. +#' +#' If a message is not supplied, it is expected that the message is +#' generated lazily through [conditionMessage()][cnd_message]. In +#' that case, `class` must be supplied. Only `inform()` allows empty +#' messages as it is occasionally useful to build user output +#' incrementally. #' @param class Subclass of the condition. This allows your users #' to selectively handle the conditions signalled by your functions. #' @param ... Additional data to be stored in the condition object. @@ -127,7 +133,7 @@ ..., trace = NULL, parent = NULL, - .subclass) { + .subclass = deprecated()) { validate_signal_args(.subclass) if (is_null(trace) && is_null(peek_option("rlang:::disable_trace_capture"))) { diff -Nru r-cran-rlang-0.4.8/R/cnd-entrace.R r-cran-rlang-0.4.10/R/cnd-entrace.R --- r-cran-rlang-0.4.8/R/cnd-entrace.R 2020-07-30 13:19:37.000000000 +0000 +++ r-cran-rlang-0.4.10/R/cnd-entrace.R 2020-12-18 09:00:51.000000000 +0000 @@ -8,7 +8,7 @@ #' condition object, without any other effect. Both functions should #' be called directly from an error handler. #' -#' Set the `error` global option to `quote(rlang::entrace())` to +#' Set the `error` global option to `rlang::entrace` to #' transform base errors to rlang errors. These enriched errors #' include a backtrace. The RProfile is a good place to set the #' handler. See [`rlang_backtrace_on_error`] for details. @@ -163,7 +163,7 @@ entrace_handle_top <- function(trace) { # Happens with ctrl-c at top-level if (!trace_length(trace)) { - return() + return(entrace_exit()) } stop_call <- sys.call(-2) @@ -175,7 +175,7 @@ # No need to do anything for rlang errors if (from_stop && (is_trace(cnd$trace) || is_true(cnd$rlang_entraced))) { - return(NULL) + return(entrace_exit()) } if (from_stop) { @@ -199,6 +199,16 @@ cat_line(backtrace_lines) } + entrace_exit() +} + +entrace_exit <- function() { + # Disable error handler in non-interactive sessions to force + # non-zero exit (#1052, rstudio/bookdown#920) + if (!is_interactive()) { + options(error = NULL) + } + NULL } @@ -249,5 +259,5 @@ with_abort <- function(expr, classes = "error") { handlers <- rep_named(classes, list(entrace)) handle_call <- rlang::expr(withCallingHandlers(expr, !!!handlers)) - .Call(rlang_eval, handle_call, current_env()) + .External2(rlang_ext2_eval, handle_call, current_env()) } diff -Nru r-cran-rlang-0.4.8/R/cnd-error.R r-cran-rlang-0.4.10/R/cnd-error.R --- r-cran-rlang-0.4.8/R/cnd-error.R 2020-07-29 15:30:05.000000000 +0000 +++ r-cran-rlang-0.4.10/R/cnd-error.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,7 +1,7 @@ #' @rdname cnd #' @export -error_cnd <- function(.subclass = NULL, +error_cnd <- function(class = NULL, ..., message = "", trace = NULL, @@ -12,8 +12,15 @@ if (!is_null(parent) && !inherits(parent, "condition")) { abort("`parent` must be NULL or a condition object") } - fields <- dots_list(trace = trace, parent = parent, ...) - .Call(rlang_new_condition, c(.subclass, "rlang_error", "error"), message, fields) + fields <- error_cnd_fields(trace = trace, parent = parent, ...) + + .Call(rlang_new_condition, c(class, "rlang_error", "error"), message, fields) +} +error_cnd_fields <- function(trace, parent, ..., .subclass = NULL, env = caller_env()) { + if (!is_null(.subclass)) { + deprecate_subclass(.subclass, env) + } + list2(trace = trace, parent = parent, ...) } #' @export @@ -27,7 +34,7 @@ simplify = c("branch", "collapse", "none"), fields = FALSE) { simplify <- arg_match(simplify) - cat_line(format(x, simplify = simplify, fields = fields)) + cat_line(format(x, simplify = simplify, fields = fields, ...)) invisible(x) } @@ -38,6 +45,7 @@ #' @export format.rlang_error <- function(x, ..., + backtrace = TRUE, child = NULL, simplify = c("branch", "collapse", "none"), fields = FALSE) { @@ -102,7 +110,7 @@ simplify <- arg_match(simplify) - if (!is_null(trace) && trace_length(trace)) { + if (backtrace && !is_null(trace) && trace_length(trace)) { out <- paste_line(out, bold("Backtrace:")) trace_lines <- format(trace, ..., simplify = simplify) out <- paste_line(out, trace_lines) @@ -181,3 +189,7 @@ bold(sprintf("", class)) } } + +on_load(s3_register("testthat::testthat_print", "rlang_error", function(x) { + print(x, backtrace = FALSE) +})) diff -Nru r-cran-rlang-0.4.8/R/cnd-handlers.R r-cran-rlang-0.4.10/R/cnd-handlers.R --- r-cran-rlang-0.4.8/R/cnd-handlers.R 2020-07-09 12:32:41.000000000 +0000 +++ r-cran-rlang-0.4.10/R/cnd-handlers.R 2020-11-19 15:26:52.000000000 +0000 @@ -96,7 +96,7 @@ expr <- expr(tryCatch(!!expr, !!!exiting)) } - .Call(rlang_eval, expr, environment()) + .External2(rlang_ext2_eval, expr, environment()) } #' @rdname with_handlers diff -Nru r-cran-rlang-0.4.8/R/cnd-message.R r-cran-rlang-0.4.10/R/cnd-message.R --- r-cran-rlang-0.4.8/R/cnd-message.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/cnd-message.R 2020-11-20 15:28:30.000000000 +0000 @@ -105,8 +105,6 @@ #' #' @description #' -#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("experimental")} -#' #' `format_error_bullets()` takes a character vector and returns a single #' string (or an empty vector if the input is empty). The elements of #' the input vector are assembled as a list of bullets, depending on diff -Nru r-cran-rlang-0.4.8/R/cnd.R r-cran-rlang-0.4.10/R/cnd.R --- r-cran-rlang-0.4.8/R/cnd.R 2020-07-20 18:57:21.000000000 +0000 +++ r-cran-rlang-0.4.10/R/cnd.R 2020-12-15 11:41:35.000000000 +0000 @@ -8,11 +8,6 @@ #' created with `error_cnd()`, `warning_cnd()` and `message_cnd()` #' inherit from `error`, `warning` or `message`. #' -#' @section Lifecycle: -#' -#' The `.type` and `.msg` arguments have been renamed to `.subclass` -#' and `message`. They are deprecated as of rlang 0.3.0. -#' #' @param class The condition subclass. #' @param ... <[dynamic][dyn-dots]> Named data fields stored inside #' the condition object. @@ -20,7 +15,6 @@ #' condition when it is signalled. #' @param trace A `trace` object created by [trace_back()]. #' @param parent A parent condition object created by [abort()]. -#' @inheritParams abort #' @seealso [cnd_signal()], [with_handlers()]. #' #' @keywords internal @@ -43,30 +37,28 @@ #' # Signalling an error condition aborts the current computation: #' err <- error_cnd("foo", message = "I am an error") #' try(cnd_signal(err)) -cnd <- function(class, ..., message = "", .subclass) { - if (!missing(.subclass)) { - deprecate_subclass(.subclass) - } +cnd <- function(class, ..., message = "") { if (missing(class)) { abort("Bare conditions must be subclassed") } - .Call(rlang_new_condition, class, message, dots_list(...)) + .Call(rlang_new_condition, class, message, cnd_fields(...)) } #' @rdname cnd #' @export -warning_cnd <- function(class = NULL, ..., message = "", .subclass) { - if (!missing(.subclass)) { - deprecate_subclass(.subclass) - } - .Call(rlang_new_condition, c(class, "warning"), message, dots_list(...)) +warning_cnd <- function(class = NULL, ..., message = "") { + .Call(rlang_new_condition, c(class, "warning"), message, cnd_fields(...)) } #' @rdname cnd #' @export -message_cnd <- function(class = NULL, ..., message = "", .subclass) { - if (!missing(.subclass)) { - deprecate_subclass(.subclass) +message_cnd <- function(class = NULL, ..., message = "") { + .Call(rlang_new_condition, c(class, "message"), message, cnd_fields(...)) +} + +cnd_fields <- function(..., .subclass = NULL, env = caller_env()) { + if (!is_null(.subclass)) { + deprecate_subclass(.subclass, env) } - .Call(rlang_new_condition, c(class, "message"), message, dots_list(...)) + dots_list(...) } #' Is object a condition? diff -Nru r-cran-rlang-0.4.8/R/cnd-signal.R r-cran-rlang-0.4.10/R/cnd-signal.R --- r-cran-rlang-0.4.8/R/cnd-signal.R 2020-07-09 12:32:41.000000000 +0000 +++ r-cran-rlang-0.4.10/R/cnd-signal.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,4 +1,4 @@ -#' Signal a condition object + #' Signal a condition object #' #' @description #' @@ -22,20 +22,9 @@ #' #' Use [cnd_type()] to determine the type of a condition. #' -#' -#' @section Lifecycle: -#' -#' * `.cnd` has been renamed to `cnd` and is deprecated as of rlang 0.3.0. -#' -#' * The `.mufflable` argument is deprecated as of rlang 0.3.0 and no -#' longer has any effect. Non-critical conditions are always -#' signalled with a muffle restart. -#' -#' * Creating a condition object with [cnd_signal()] is deprecated as -#' of rlang 0.3.0. Please use [signal()] instead. -#' -#' @param cnd A condition object (see [cnd()]). -#' @param .cnd,.mufflable These arguments are deprecated. +#' @param cnd A condition object (see [cnd()]). If `NULL`, +#' `cnd_signal()` returns without signalling a condition. +#' @param ... These dots are for extensions and must be empty. #' @seealso [abort()], [warn()] and [inform()] for creating and #' signalling structured R conditions. See [with_handlers()] for #' establishing condition handlers. @@ -49,8 +38,12 @@ #' # If it inherits from "error", an error is raised: #' cnd <- error_cnd("my_error_class", message = "This is an error") #' try(cnd_signal(cnd)) -cnd_signal <- function(cnd, .cnd, .mufflable) { - validate_cnd_signal_args(cnd, .cnd, .mufflable) +cnd_signal <- function(cnd, ...) { + validate_cnd_signal_args(cnd, ...) + if (is_null(cnd)) { + return(invisible(NULL)) + } + if (inherits(cnd, "rlang_error") && is_null(cnd$trace)) { trace <- trace_back() cnd$trace <- trace_trim_context(trace, trace_length(trace)) @@ -59,8 +52,14 @@ invisible(.Call(rlang_cnd_signal, cnd)) } } -validate_cnd_signal_args <- function(cnd, .cnd, .mufflable, +validate_cnd_signal_args <- function(cnd, + ..., + .cnd, + .mufflable, env = parent.frame()) { + if (dots_n(...)) { + abort("`...` must be empty.") + } if (is_character(cnd)) { warn_deprecated(paste_line( "Creating a condition with `cnd_signal()` is deprecated as of rlang 0.3.0.", @@ -104,7 +103,7 @@ ..., .frequency = c("always", "regularly", "once"), .frequency_id = NULL, - .subclass) { + .subclass = deprecated()) { validate_signal_args(.subclass) message <- validate_signal_message(message, class) @@ -128,7 +127,10 @@ #' By default, `inform()` prints to standard output in interactive #' sessions and standard error otherwise. This way IDEs can treat #' messages distinctly from warnings and errors, and R scripts can -#' still filter out the messages easily by redirecting `stderr`. +#' still filter out the messages easily by redirecting `stderr`. If +#' a sink is active, either on output or on messages, messages are +#' printed to `stderr`. This ensures consistency of behaviour in +#' interactive and non-interactive sessions. #' @export inform <- function(message = NULL, class = NULL, @@ -136,45 +138,49 @@ .file = NULL, .frequency = c("always", "regularly", "once"), .frequency_id = NULL, - .subclass) { + .subclass = deprecated()) { validate_signal_args(.subclass) - message <- message %||% "" - message <- collapse_cnd_message(message) - message <- paste0(message, "\n") - .frequency <- arg_match(.frequency, c("always", "regularly", "once")) - - if (needs_signal(.frequency, .frequency_id, message_freq_env)) { - message <- add_message_freq(message, .frequency, "message") - } else { + if (!needs_signal(.frequency, .frequency_id, message_freq_env)) { return(invisible(NULL)) } + message <- message %||% "" + message <- collapse_cnd_message(message) + message <- add_message_freq(message, .frequency, "message") + message <- paste0(message, "\n") + cnd <- message_cnd(class, ..., message = message) withRestarts(muffleMessage = function() NULL, { signalCondition(cnd) - - .file <- .file %||% if (is_interactive()) stdout() else stderr() - cat(message, file = .file) + cat(message, file = .file %||% default_message_file()) }) invisible() } #' @rdname abort #' @export -signal <- function(message, class, ..., .subclass) { - if (!missing(.subclass)) { - deprecate_subclass(.subclass) - } +signal <- function(message, class, ..., .subclass = deprecated()) { + validate_signal_args(.subclass) message <- collapse_cnd_message(message) cnd <- cnd(class, ..., message = message) cnd_signal(cnd) } +default_message_file <- function() { + if (is_interactive() && + sink.number("output") == 0 && + sink.number("message") == 2) { + stdout() + } else { + stderr() + } +} + validate_signal_args <- function(subclass, env = caller_env()) { - if (!missing(subclass)) { + if (!is_missing(subclass)) { deprecate_subclass(subclass, env = env) } } diff -Nru r-cran-rlang-0.4.8/R/compat-zeallot.R r-cran-rlang-0.4.10/R/compat-zeallot.R --- r-cran-rlang-0.4.8/R/compat-zeallot.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/R/compat-zeallot.R 2020-11-24 11:21:07.000000000 +0000 @@ -0,0 +1,34 @@ +# nocov start --- compat-zeallot --- 2020-11-23 + +# This drop-in file implements a simple version of zeallot::`%<-%`. +# Please find the most recent version in rlang's repository. + + +`%<-%` <- function(lhs, value) { + lhs <- substitute(lhs) + env <- caller_env() + + if (!is_call(lhs, "c")) { + abort("The left-hand side of `%<-%` must be a call to `c()`.") + } + + vars <- as.list(lhs[-1]) + + if (length(value) != length(vars)) { + abort("The left- and right-hand sides of `%<-%` must be the same length.") + } + + for (i in seq_along(vars)) { + var <- vars[[i]] + if (!is_symbol(var)) { + abort(paste0("Element ", i, " of the left-hand side of `%<-%` must be a symbol.")) + } + + env[[as_string(var)]] <- value[[i]] + } + + invisible(value) +} + + +# nocov end diff -Nru r-cran-rlang-0.4.8/R/deparse.R r-cran-rlang-0.4.10/R/deparse.R --- r-cran-rlang-0.4.8/R/deparse.R 2020-07-09 12:32:41.000000000 +0000 +++ r-cran-rlang-0.4.10/R/deparse.R 2020-12-18 09:00:51.000000000 +0000 @@ -286,6 +286,14 @@ lines$deparse(node_cadr(x)) lines$get_lines() } +next_deparse <- function(x, lines = new_lines()) { + lines$push("next") + lines$get_lines() +} +break_deparse <- function(x, lines = new_lines()) { + lines$push("break") + lines$get_lines() +} if_deparse <- function(x, lines = new_lines()) { x <- node_cdr(x) lines$push("if (") @@ -322,7 +330,7 @@ } } -binary_op_deparse <- function(x, lines = new_lines(), space = " ") { +binary_op_deparse <- function(x, lines = new_lines(), space = " ", sticky_rhs = FALSE) { # Constructed call without second argument if (is_null(node_cddr(x))) { return(call_deparse(x, lines)) @@ -336,6 +344,10 @@ lines$push_sticky(paste0(space, op, space)) + if (sticky_rhs) { + lines$make_next_sticky() + } + x <- node_cdr(x) lines$increase_indent() @@ -350,6 +362,9 @@ unspaced_op_deparse <- function(x, lines = new_lines()) { binary_op_deparse(x, lines, space = "") } +tight_op_deparse <- function(x, lines = new_lines()) { + binary_op_deparse(x, lines, space = "", sticky_rhs = TRUE) +} unary_op_deparse <- function(x, lines = new_lines()) { op <- as_string(node_car(x)) @@ -531,6 +546,8 @@ `for` = for_deparse, `repeat` = repeat_deparse, `if` = if_deparse, + `next` = next_deparse, + `break` = break_deparse, `?` = , `<-` = , `<<-` = , @@ -556,9 +573,9 @@ `:` = , `^` = , `$` = , - `@` = , + `@` = unspaced_op_deparse, `::` = , - `:::` = unspaced_op_deparse, + `:::` = tight_op_deparse, `?unary` = , `~unary` = , `!` = , diff -Nru r-cran-rlang-0.4.8/R/dots.R r-cran-rlang-0.4.10/R/dots.R --- r-cran-rlang-0.4.8/R/dots.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/dots.R 2020-12-18 09:00:51.000000000 +0000 @@ -15,8 +15,9 @@ #' 1. You can __splice__ arguments saved in a list with the [big #' bang][quasiquotation] operator `!!!`. #' -#' 2. You can __unquote__ names by using the [bang bang][quasiquotation] -#' operator `!!` on the left-hand side of `:=`. +#' 2. You can __unquote__ names by using the [glue][glue::glue] syntax +#' or the [bang bang][quasiquotation] operator `!!` on the +#' left-hand side of `:=`. #' #' 3. Trailing commas are ignored, making it easier to copy and paste #' lines of arguments. @@ -31,6 +32,12 @@ #' configurable than [list2()], `vars()` which doesn't force its #' arguments, and [call2()] for creating calls. #' +#' Document dynamic docs using this standard tag: +#' +#' ``` +#' @@param ... <[`dynamic-dots`][rlang::dyn-dots]> What these dots do. +#' ``` +#' #' @name dyn-dots #' @aliases tidy-dots #' @@ -386,7 +393,8 @@ .preserve_empty = FALSE, .homonyms = c("keep", "first", "last", "error"), .check_assign = FALSE) { - .External2(rlang_ext2_dots_values, + .External(rlang_ext_dots_values, + env = environment(), named = FALSE, ignore_empty = .ignore_empty, preserve_empty = .preserve_empty, diff -Nru r-cran-rlang-0.4.8/R/env-binding.R r-cran-rlang-0.4.10/R/env-binding.R --- r-cran-rlang-0.4.8/R/env-binding.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/env-binding.R 2020-11-23 12:47:48.000000000 +0000 @@ -34,6 +34,9 @@ #' bound to the symbol (the expressions are thus evaluated only #' once, if at all). #' +#' - `%<~%` is a shortcut for `env_bind_lazy()`. It works like `<-` +#' but the RHS is evaluated lazily. +#' #' #' @section Side effects: #' @@ -220,6 +223,18 @@ eval_env = caller_env() )) } +#' @rdname env_bind +#' @param lhs The variable name to which `rhs` will be lazily assigned. +#' @param rhs An expression lazily evaluated and assigned to `lhs`. +#' @export +`%<~%` <- function(lhs, rhs) { + env_bind_lazy( + env, + !!substitute(lhs) := !!substitute(rhs), + .eval_env = caller_env() + ) +} + #' Temporarily change bindings of an environment #' @@ -274,8 +289,7 @@ #' `inherit` to `TRUE` to track down bindings in parent environments. #' #' @inheritParams get_env -#' @param nms A character vector containing the names of the bindings -#' to remove. +#' @param nms A character vector of binding names to remove. #' @param inherit Whether to look for bindings in the parent #' environments. #' @return The input object `env` with its associated environment @@ -310,6 +324,8 @@ #' any of its parents (with `inherit = TRUE`). #' #' @inheritParams env_unbind +#' @param nms A character vector of binding names for which to check +#' existence. #' @return A named logical vector as long as `nms`. #' @export #' @examples diff -Nru r-cran-rlang-0.4.8/R/env.R r-cran-rlang-0.4.10/R/env.R --- r-cran-rlang-0.4.8/R/env.R 2020-10-07 09:50:17.000000000 +0000 +++ r-cran-rlang-0.4.10/R/env.R 2020-11-20 15:44:20.000000000 +0000 @@ -639,6 +639,12 @@ #' #' * Locked bindings get a `[L]` tag #' +#' Note that printing a package namespace (see [ns_env()]) with +#' `env_print()` will typically tag function bindings as `` +#' until they are evaluated the first time. This is because package +#' functions are lazily-loaded from disk to improve performance when +#' loading a package. +#' #' @param env An environment, or object that can be converted to an #' environment by [get_env()]. #' @@ -775,3 +781,28 @@ } invisible(object) } + +#' Browse environments +#' +#' @description +#' +#' * `env_browse(env)` is equivalent to evaluating `browser()` in +#' `env`. It persistently sets the environment for step-debugging. +#' Supply `value = FALSE` to disable browsing. +#' +#' * `env_is_browsed()` is a predicate that inspects whether an +#' environment is being browsed. +#' +#' @param env An environment. +#' @param value Whether to browse `env`. +#' @return `env_browse()` returns the previous value of +#' `env_is_browsed()` (a logical), invisibly. +#' @export +env_browse <- function(env, value = TRUE) { + invisible(.Call(rlang_env_browse, env, value)) +} +#' @rdname env_browse +#' @export +env_is_browsed <- function(env) { + .Call(rlang_env_is_browsed, env) +} diff -Nru r-cran-rlang-0.4.8/R/env-special.R r-cran-rlang-0.4.10/R/env-special.R --- r-cran-rlang-0.4.8/R/env-special.R 2020-07-09 12:32:41.000000000 +0000 +++ r-cran-rlang-0.4.10/R/env-special.R 2020-12-18 09:00:51.000000000 +0000 @@ -22,6 +22,10 @@ #' and throws an error otherwise. It is a shortcut for #' `search_env(pkg_env_name("pkgname"))`. #' +#' - `global_env()` and `base_env()` (simple aliases for [globalenv()] +#' and [baseenv()]). These are respectively the first and last +#' environments of the search path. +#' #' - `is_attached()` returns `TRUE` when its argument (a search name #' or a package environment) is attached to the search path. #' @@ -32,8 +36,8 @@ #' the global workspace. It contains the following elements: #' #' - The chain always starts with `global_env()` and finishes with -#' `base_env()` (technically, it finishes with the `empty_env()` -#' which the base package environment inherits from). +#' `base_env()` which inherits from the terminal environment +#' `empty_env()`. #' #' - Each [base::library()] call attaches a new package environment to #' the search path. Attached packages are associated with a [search @@ -270,12 +274,30 @@ #' Are packages installed in any of the libraries? #' -#' This checks that packages are installed with minimal side effects. -#' If installed, the packages will be loaded but not attached. +#' @description +#' These functions check that packages are installed with minimal side +#' effects. If installed, the packages will be loaded but not +#' attached. +#' +#' - `is_installed()` doesn't interact with the user. It simply +#' returns `TRUE` or `FALSE` depending on whether the packages are +#' installed. +#' +#' - In interactive sessions, `check_installed()` asks the user +#' whether to install missing packages. If the user accepts, the +#' packages are installed with `pak::pkg_install()` if available, or +#' [utils::install.packages()] otherwise. If the session is non +#' interactive or if the user chooses not to install the packages, +#' the current evaluation is aborted. #' #' @param pkg The package names. -#' @return `TRUE` if _all_ package names provided in `pkg` are installed, -#' `FALSE` otherwise. +#' @param reason Optional string indicating why is `pkg` needed. +#' Appears in error messages (if non-interactive) and user prompts +#' (if interactive). +#' @return `is_installed()` returns `TRUE` if _all_ package names +#' provided in `pkg` are installed, `FALSE` +#' otherwise. `check_installed()` either doesn't return or returns +#' `NULL`. #' @export #' @examples #' is_installed("utils") @@ -283,7 +305,58 @@ is_installed <- function(pkg) { all(map_lgl(pkg, function(x) is_true(requireNamespace(x, quietly = TRUE)))) } +#' @rdname is_installed +#' @export +check_installed <- function(pkg, reason = NULL) { + if (!is_character(pkg)) { + abort("`pkg` must be a package name or a vector of package names.") + } + needs_install <- !map_lgl(pkg, function(x) is_true(requireNamespace(x, quietly = TRUE))) + + if (any(needs_install)) { + missing_pkgs <- pkg[needs_install] + missing_pkgs_enum <- chr_enumerate(chr_quoted(missing_pkgs), final = "and") + + n <- length(missing_pkgs) + info <- pluralise( + n, + paste0("The ", missing_pkgs_enum, " package is required"), + paste0("The ", missing_pkgs_enum, " packages are required") + ) + if (is_null(reason)) { + info <- paste0(info, ".") + } else { + info <- paste(info, reason) + } + + question <- pluralise( + n, + "Would you like to install it?", + "Would you like to install them?" + ) + + if (!is_interactive()) { + abort(info) + } + + cat(paste_line( + paste0(info(), " ", info), + paste0(cross(), " ", question), + .trailing = TRUE + )) + + if (utils::menu(c("Yes", "No")) != 1) { + invokeRestart("abort") + } + if (is_installed("pak")) { + pak::pkg_install(missing_pkgs, ask = FALSE) + } else { + utils::install.packages(missing_pkgs) + } + } + invisible(NULL) +} env_type <- function(env) { if (is_reference(env, global_env())) { @@ -392,3 +465,9 @@ sexp_address(env) } } + +# This does not behave like a normal environment because the parent is +# NULL instead of the empty env +ns_registry_env <- function() { + .Call(rlang_ns_registry_env) +} diff -Nru r-cran-rlang-0.4.8/R/eval.R r-cran-rlang-0.4.10/R/eval.R --- r-cran-rlang-0.4.8/R/eval.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/eval.R 2020-11-19 16:04:34.000000000 +0000 @@ -96,7 +96,7 @@ #' # But that's not the case with base::eval(): #' fn(base::eval) eval_bare <- function(expr, env = parent.frame()) { - .Call(rlang_eval, expr, env) + .External2(rlang_ext2_eval, expr, env) } #' Evaluate an expression within a given environment @@ -154,12 +154,12 @@ #' # This can be handy to put dictionaries in scope: #' with_env(mtcars, cyl) with_env <- function(env, expr) { - .Call(rlang_eval, substitute(expr), as_environment(env, caller_env())) + .External2(rlang_ext2_eval, substitute(expr), as_environment(env, caller_env())) } #' @rdname with_env #' @export locally <- function(expr) { - .Call(rlang_eval, substitute(expr), child_env(caller_env())) + .External2(rlang_ext2_eval, substitute(expr), child_env(caller_env())) } #' Invoke a function with a list of arguments @@ -242,7 +242,7 @@ .fn <- env_get(.env, .fn, inherit = TRUE) } call <- call2(.fn, !!! args) - return(.Call(rlang_eval, call, .env)) + return(.External2(rlang_ext2_eval, call, .env)) } @@ -264,7 +264,7 @@ } call <- call2(.fn, !!! args) - .Call(rlang_eval, call, .env) + .External2(rlang_ext2_eval, call, .env) } value <- function(expr) { @@ -323,3 +323,47 @@ exec <- function(.fn, ..., .env = caller_env()) { .External2(rlang_ext2_exec, .fn, .env) } + +#' Inject objects in an R expression +#' +#' `inject()` evaluates an expression with [injection][quasiquotation] +#' (unquotation) support. There are three main usages: +#' +#' - [Splicing][!!!] lists of arguments in a function call. +#' +#' - Inline objects or other expressions in an expression with `!!` +#' and `!!!`. For instance to create functions or formulas +#' programmatically. +#' +#' - Pass arguments to NSE functions that [defuse][nse-defuse] their +#' arguments without injection support (see for instance +#' [enquo0()]). You can use `{{ arg }}` with functions documented +#' to support quosures. Otherwise, use `!!enexpr(arg)`. +#' +#' @param expr An argument to evaluate. This argument is immediately +#' evaluated in `env` (the current environment by default) with +#' injected objects and expressions. +#' @param env The environment in which to evaluate `expr`. Defaults to +#' the current environment. For expert use only. +#' +#' @export +#' @examples +#' # inject() simply evaluates its argument with injection +#' # support. These expressions are equivalent: +#' 2 * 3 +#' inject(2 * 3) +#' inject(!!2 * !!3) +#' +#' # Injection with `!!` can be useful to insert objects or +#' # expressions within other expressions, like formulas: +#' lhs <- sym("foo") +#' rhs <- sym("bar") +#' inject(!!lhs ~ !!rhs + 10) +#' +#' # Injection with `!!!` splices lists of arguments in function +#' # calls: +#' args <- list(na.rm = TRUE, finite = 0.2) +#' inject(mean(1:10, !!!args)) +inject <- function(expr, env = caller_env()) { + .External2(rlang_ext2_eval, enexpr(expr), env) +} diff -Nru r-cran-rlang-0.4.8/R/eval-tidy.R r-cran-rlang-0.4.10/R/eval-tidy.R --- r-cran-rlang-0.4.8/R/eval-tidy.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/eval-tidy.R 2020-12-18 09:00:51.000000000 +0000 @@ -94,15 +94,20 @@ #' #' @section Stack semantics of `eval_tidy()`: #' -#' `eval_tidy()` has different stack semantics than [base::eval()]: +#' `eval_tidy()` always evaluates in a data mask, even when `data` is +#' `NULL`. Because of this, it has different stack semantics than +#' [base::eval()]: +#' +#' - Lexical side effects, such as assignment with `<-`, occur in the +#' mask rather than `env`. #' #' - Functions that require the evaluation environment to correspond #' to a frame on the call stack do not work. This is why `return()` #' called from a quosure does not work. #' -#' - The mask environment creates a new branch in the call tree -#' defined by `sys.parent()` (you can visualise it in a [browser()] -#' session with `lobstr::cst()`). +#' - The mask environment creates a new branch in the tree +#' representation of backtraces (which you can visualise in a +#' [browser()] session with `lobstr::cst()`). #' #' See also [eval_bare()] for more information about these differences. #' @@ -165,7 +170,7 @@ #' } #' @export eval_tidy <- function(expr, data = NULL, env = caller_env()) { - .Call(rlang_eval_tidy, expr, data, env) + .External2(rlang_ext2_eval_tidy, expr, data, env) } # Helps work around roxygen loading issues @@ -219,6 +224,7 @@ #' @export .data <- structure(list(), class = "rlang_fake_data_pronoun") #' @rdname tidyeval-data +#' @format NULL #' @export .env <- .data diff -Nru r-cran-rlang-0.4.8/R/fn.R r-cran-rlang-0.4.10/R/fn.R --- r-cran-rlang-0.4.8/R/fn.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/fn.R 2020-11-19 12:47:54.000000000 +0000 @@ -430,7 +430,9 @@ } if (is_quosure(x)) { - return(eval(expr(function(...) eval_tidy(!!x)))) + mask <- eval_tidy(call2(environment), env = quo_get_env(x)) + fn <- new_function(pairlist2(... = ), quo_get_expr(x), mask) + return(fn) } if (is_formula(x)) { diff -Nru r-cran-rlang-0.4.8/R/hash.R r-cran-rlang-0.4.10/R/hash.R --- r-cran-rlang-0.4.8/R/hash.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/R/hash.R 2020-12-18 09:31:10.000000000 +0000 @@ -0,0 +1,26 @@ +#' Hash an object +#' +#' @description +#' `hash()` hashes an arbitrary R object. +#' +#' The generated hash is guaranteed to be reproducible across platforms, but +#' not across R versions. +#' +#' @details +#' `hash()` uses the XXH128 hash algorithm of the xxHash library, which +#' generates a 128-bit hash. It is implemented as a streaming hash, which +#' generates the hash with minimal extra memory usage. +#' +#' Objects are converted to binary using R's native serialization tools. +#' On R >= 3.5.0, serialization version 3 is used, otherwise version 2 is used. +#' See [serialize()] for more information about the serialization version. +#' +#' @param x An object. +#' +#' @export +#' @examples +#' hash(c(1, 2, 3)) +#' hash(mtcars) +hash <- function(x) { + .Call(rlang_hash, x) +} diff -Nru r-cran-rlang-0.4.8/R/lifecycle.R r-cran-rlang-0.4.10/R/lifecycle.R --- r-cran-rlang-0.4.8/R/lifecycle.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/lifecycle.R 2020-11-20 16:00:42.000000000 +0000 @@ -190,3 +190,5 @@ #' @keywords internal #' @name lifecycle NULL + +deprecated <- function() missing_arg() diff -Nru r-cran-rlang-0.4.8/R/lifecycle-retired.R r-cran-rlang-0.4.10/R/lifecycle-retired.R --- r-cran-rlang-0.4.8/R/lifecycle-retired.R 2020-08-12 08:53:52.000000000 +0000 +++ r-cran-rlang-0.4.10/R/lifecycle-retired.R 2020-11-19 17:11:47.000000000 +0000 @@ -1168,7 +1168,7 @@ "`overscope_eval_next()` is deprecated as of rlang 0.2.0.", "Please use `eval_tidy()` with a data mask instead." )) - .Call(rlang_eval_tidy, quo, overscope, env) + .External2(rlang_ext2_eval_tidy, quo, overscope, env) } diff -Nru r-cran-rlang-0.4.8/R/node.R r-cran-rlang-0.4.10/R/node.R --- r-cran-rlang-0.4.8/R/node.R 2020-08-12 09:15:35.000000000 +0000 +++ r-cran-rlang-0.4.10/R/node.R 2020-12-18 09:00:51.000000000 +0000 @@ -87,6 +87,20 @@ invisible(.Call(rlang_node_poke_cddr, x, newcdr)) } +node_get <- function(node, i) { + if (node < 1L) { + abort("`i` must be an integer greater than 0.") + } + while (i > 1L) { + node <- node_cdr(node) + i <- i - 1L + } + node +} +node_get_car <- function(node, i) { + node_car(node_get(node, i)) +} + #' @rdname new_node #' @export node_tag <- function(x) { diff -Nru r-cran-rlang-0.4.8/R/nse-defuse.R r-cran-rlang-0.4.10/R/nse-defuse.R --- r-cran-rlang-0.4.8/R/nse-defuse.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/nse-defuse.R 2020-11-19 16:46:07.000000000 +0000 @@ -120,6 +120,8 @@ #' `:=` syntax supports `!!` unquoting on the LHS. #' @name nse-defuse #' @aliases quotation +#' @seealso [enquo0()] and [enquos0()] for variants that do not +#' perform automatic injection/unquotation. #' @examples #' # expr() and exprs() capture expressions that you supply: #' expr(symbol) @@ -435,3 +437,48 @@ quos_auto_name <- function(quos, width = NULL) { exprs_auto_name(quos, width = width) } + + +captureArgInfo <- function(arg) { + .External(rlang_ext_capturearginfo, environment(), parent.frame()) +} +captureDots <- function() { + .External(rlang_ext_capturedots, parent.frame()) +} + + +#' Defuse arguments without automatic injection +#' +#' The 0-suffixed variants of [enquo()] and [enquos()] defuse function +#' arguments without automatic injection (unquotation). They are +#' useful when defusing expressions that potentially include `!!`, +#' `!!!`, or `{{` operations, for instance tidyverse code. In that +#' case, `enquo()` would process these operators too early, creating a +#' confusing experience for users. Callers can still inject objects +#' or expressions using manual injection with [inject()]. +#' +#' None of the features of [dynamic dots][dyn-dots] are available when +#' defusing with `enquos0()`. For instance, trailing empty arguments +#' are not automatically trimmed. +#' +#' @param arg A symbol for a function argument to defuse. +#' @param ... Dots to defuse. +#' +#' @seealso [enquo()] and [enquos()] +#' @examples +#' automatic_injection <- function(x) enquo(x) +#' no_injection <- function(x) enquo0(x) +#' +#' automatic_injection(foo(!!!1:3)) +#' no_injection(foo(!!!1:3)) +#' @export +enquo0 <- function(arg) { + info <- .External(rlang_ext_capturearginfo, environment(), parent.frame()) + as_quosure(info$expr, info$env) +} +#' @rdname enquo0 +#' @export +enquos0 <- function(...) { + dots <- .External(rlang_ext_capturedots, environment()) + lapply(dots, function(dot) as_quosure(dot$expr, dot$env)) +} diff -Nru r-cran-rlang-0.4.8/R/parse.R r-cran-rlang-0.4.10/R/parse.R --- r-cran-rlang-0.4.8/R/parse.R 2020-07-09 15:02:36.000000000 +0000 +++ r-cran-rlang-0.4.10/R/parse.R 2020-11-23 12:47:48.000000000 +0000 @@ -1,15 +1,28 @@ #' Parse R code #' +#' @description #' These functions parse and transform text into R expressions. This #' is the first step to interpret or evaluate a piece of R code #' written by a programmer. #' -#' `parse_expr()` returns one expression. If the text contains more -#' than one expression (separated by semicolons or new lines), an error is -#' issued. On the other hand `parse_exprs()` can handle multiple -#' expressions. It always returns a list of expressions (compare to -#' [base::parse()] which returns a base::expression vector). All -#' functions also support R connections. +#' * `parse_expr()` returns one expression. If the text contains more +#' than one expression (separated by semicolons or new lines), an +#' error is issued. On the other hand `parse_exprs()` can handle +#' multiple expressions. It always returns a list of expressions +#' (compare to [base::parse()] which returns a base::expression +#' vector). All functions also support R connections. +#' +#' * `parse_quo()` and `parse_quos()` are variants that create a +#' [quosure][quo] that inherits from the global environment by +#' default. This is appropriate when you're parsing external user +#' input to be evaluated in user context (rather than the private +#' contexts of your functions). +#' +#' Unlike quosures created with [enquo()], [enquos()], or `{{`, a +#' parsed quosure never contains injected quosures. It is thus safe +#' to evaluate them with `eval()` instead of [eval_tidy()], though +#' the latter is more convenient as you don't need to extract `expr` +#' and `env`. #' #' @param x Text containing expressions to parse_expr for #' `parse_expr()` and `parse_exprs()`. Can also be an R connection, @@ -21,6 +34,7 @@ #' length of the input. This would happen is one of the strings #' contain several expressions (such as `"foo; bar"`). The names of #' `x` are preserved (and recycled in case of multiple expressions). +#' The `_quo` suffixed variants return quosures. #' @seealso [base::parse()] #' @export #' @examples @@ -83,31 +97,22 @@ set_names(parsed, nms) } -#' Parsing variants that return quosures -#' -#' @description -#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("questioning")} -#' -#' These functions are in the questioning stage because they don't add -#' value compared to using [parse_expr()] with [new_quosure()]. -#' -#' @inheritParams parse_expr -#' @param env The environment for the quosures. Depending on the use -#' case, a good default might be the [global -#' environment][global_env] but you might also want to evaluate the -#' R code in an isolated context (perhaps a child of the global -#' environment or of the [base environment][base_env]). -#' @keywords internal +#' @rdname parse_expr +#' @param env The environment for the quosures. The [global +#' environment][global_env] (the default) may be the right choice +#' when you are parsing external user inputs. You might also want to +#' evaluate the R code in an isolated context (perhaps a child of +#' the global environment or of the [base environment][base_env]). #' @export -parse_quo <- function(x, env) { +parse_quo <- function(x, env = global_env()) { if (missing(env)) { abort("The quosure environment should be explicitly supplied as `env`") } new_quosure(parse_expr(x), as_environment(env)) } -#' @rdname parse_quo +#' @rdname parse_expr #' @export -parse_quos <- function(x, env) { +parse_quos <- function(x, env = global_env()) { if (missing(env)) { abort("The quosure environment should be explicitly supplied as `env`") } diff -Nru r-cran-rlang-0.4.8/R/rlang.R r-cran-rlang-0.4.10/R/rlang.R --- r-cran-rlang-0.4.8/R/rlang.R 2020-07-09 12:32:41.000000000 +0000 +++ r-cran-rlang-0.4.10/R/rlang.R 2020-12-18 09:00:51.000000000 +0000 @@ -28,6 +28,8 @@ .Call(r_init_library) .Call(rlang_library_load, ns_env("rlang")) + run_on_load() + s3_register("pillar::pillar_shaft", "quosures", pillar_shaft.quosures) s3_register("pillar::type_sum", "quosures", type_sum.quosures) diff -Nru r-cran-rlang-0.4.8/R/utils.R r-cran-rlang-0.4.10/R/utils.R --- r-cran-rlang-0.4.8/R/utils.R 2020-07-09 12:32:41.000000000 +0000 +++ r-cran-rlang-0.4.10/R/utils.R 2020-11-20 11:08:50.000000000 +0000 @@ -72,15 +72,6 @@ } } -captureArgInfo <- function(x) { - args <- pairlist(parent.frame()) - .Call(rlang_capturearginfo, NULL, NULL, args, environment()) -} -captureDots <- function() { - args <- pairlist(parent.frame()) - .Call(rlang_capturedots, NULL, NULL, args, environment()) -} - cat_line <- function(..., .trailing = TRUE, file = "") { cat(paste_line(..., .trailing = .trailing), file = file) } @@ -270,3 +261,11 @@ stop_internal <- function(fn, msg) { abort(sprintf("Internal error in `%s()`: %s"), fn, msg) } + +with_srcref <- function(src, env = caller_env(), file = NULL) { + file <- file %||% tempfile("sourced", fileext = ".R") + on.exit(unlink(file)) + + writeLines(src, file) + source(file, local = env, keep.source = TRUE) +} diff -Nru r-cran-rlang-0.4.8/src/capture.c r-cran-rlang-0.4.10/src/capture.c --- r-cran-rlang-0.4.8/src/capture.c 2019-04-23 12:33:50.000000000 +0000 +++ r-cran-rlang-0.4.10/src/capture.c 2020-11-19 15:01:15.000000000 +0000 @@ -53,7 +53,7 @@ int nProt = 0; // Unwrap first layer of promise - SEXP sym = findVarInFrame3(rho, install("x"), TRUE); + SEXP sym = findVarInFrame3(rho, install("arg"), TRUE); PROTECT(sym); ++nProt; // May be a literal if compiler did not wrap in a promise diff -Nru r-cran-rlang-0.4.8/src/export/exported.c r-cran-rlang-0.4.10/src/export/exported.c --- r-cran-rlang-0.4.8/src/export/exported.c 2020-10-06 08:56:24.000000000 +0000 +++ r-cran-rlang-0.4.10/src/export/exported.c 2020-11-19 16:16:47.000000000 +0000 @@ -1,4 +1,5 @@ #include +#include "../internal/utils.h" // attrs.c @@ -96,11 +97,36 @@ return r_null; } +sexp* rlang_env_browse(sexp* env, sexp* value) { + if (r_typeof(env) != r_type_environment) { + r_abort("`env` must be an environment."); + } + if (!r_is_bool(value)) { + r_abort("`value` must be a single logical value."); + } + + sexp* old = r_lgl(RDEBUG(env)); + SET_RDEBUG(env, r_lgl_get(value, 0)); + return old; +} + +sexp* rlang_env_is_browsed(sexp* env) { + if (r_typeof(env) != r_type_environment) { + r_abort("`env` must be an environment."); + } + return r_lgl(RDEBUG(env)); +} + +sexp* rlang_ns_registry_env() { + return R_NamespaceRegistry; +} + // eval.c -sexp* rlang_eval(sexp* expr, sexp* env) { - return Rf_eval(expr, env); +sexp* rlang_ext2_eval(sexp* call, sexp* op, sexp* args, sexp* env) { + args = r_node_cdr(args); + return Rf_eval(r_node_car(args), r_node_cadr(args)); } sexp* rlang_eval_top(sexp* expr, sexp* env) { diff -Nru r-cran-rlang-0.4.8/src/export/init.c r-cran-rlang-0.4.10/src/export/init.c --- r-cran-rlang-0.4.8/src/export/init.c 2020-08-12 09:15:35.000000000 +0000 +++ r-cran-rlang-0.4.10/src/export/init.c 2020-12-18 09:31:10.000000000 +0000 @@ -40,7 +40,6 @@ extern sexp* r_node_tree_clone(sexp*); extern sexp* rlang_node_tag(sexp*); extern sexp* rlang_node_poke_tag(sexp*, sexp*); -extern sexp* rlang_eval(sexp*, sexp*); extern sexp* rlang_interp(sexp*, sexp*); extern sexp* rlang_is_function(sexp*); extern sexp* rlang_is_closure(sexp*); @@ -98,7 +97,6 @@ extern sexp* rlang_as_data_mask(sexp*); extern sexp* rlang_as_data_mask_compat(sexp*, sexp*); extern sexp* rlang_data_mask_clean(sexp*); -extern sexp* rlang_eval_tidy(sexp*, sexp*, sexp*); extern sexp* rlang_as_data_pronoun(sexp*); extern sexp* rlang_env_get(sexp*, sexp*, sexp*, sexp*); extern sexp* rlang_env_get_list(sexp*, sexp*, sexp*, sexp*); @@ -142,6 +140,11 @@ extern sexp* rlang_env_poke(sexp*, sexp*, sexp*, sexp*, sexp*); extern sexp* rlang_env_bind(sexp*, sexp*, sexp*, sexp*, sexp*); extern sexp* rlang_raw_deparse_str(sexp*, sexp*, sexp*); +extern sexp* rlang_env_browse(sexp*, sexp*); +extern sexp* rlang_env_is_browsed(sexp*); +extern sexp* rlang_ns_registry_env(); +extern sexp* rlang_hash(sexp*); + // Library initialisation defined below sexp* rlang_library_load(sexp*); @@ -178,7 +181,6 @@ {"rlang_capturedots", (r_fn_ptr) &rlang_capturedots, 4}, {"rlang_duplicate", (r_fn_ptr) &rlang_duplicate, 2}, {"rlang_node_tree_clone", (r_fn_ptr) &r_node_tree_clone, 1}, - {"rlang_eval", (r_fn_ptr) &rlang_eval, 2}, {"rlang_interp", (r_fn_ptr) &rlang_interp, 2}, {"rlang_is_function", (r_fn_ptr) &rlang_is_function, 1}, {"rlang_is_closure", (r_fn_ptr) &rlang_is_closure, 1}, @@ -224,6 +226,8 @@ {"rlang_sexp_address", (r_fn_ptr) &rlang_sexp_address, 1}, {"rlang_symbol", (r_fn_ptr) &rlang_symbol, 1}, {"rlang_sym_as_character", (r_fn_ptr) &rlang_sym_as_character, 1}, + // No longer necessary but keep this around for a while in case + // quosures ended up saved as RDS. {"rlang_tilde_eval", (r_fn_ptr) &rlang_tilde_eval, 3}, {"rlang_unescape_character", (r_fn_ptr) &rlang_unescape_character, 1}, {"rlang_new_call", (r_fn_ptr) &rlang_new_call_node, 2}, @@ -277,7 +281,6 @@ {"rlang_is_data_mask", (r_fn_ptr) &rlang_is_data_mask, 1}, {"rlang_data_pronoun_get", (r_fn_ptr) &rlang_data_pronoun_get, 2}, {"rlang_data_mask_clean", (r_fn_ptr) &rlang_data_mask_clean, 1}, - {"rlang_eval_tidy", (r_fn_ptr) &rlang_eval_tidy, 3}, {"rlang_as_data_pronoun", (r_fn_ptr) &rlang_as_data_pronoun, 1}, {"rlang_env_binding_types", (r_fn_ptr) &r_env_binding_types, 2}, {"rlang_env_get", (r_fn_ptr) &rlang_env_get, 4}, @@ -318,25 +321,37 @@ {"rlang_env_poke", (r_fn_ptr) &rlang_env_poke, 5}, {"rlang_env_bind", (r_fn_ptr) &rlang_env_bind, 5}, {"rlang_raw_deparse_str", (r_fn_ptr) &rlang_raw_deparse_str, 3}, + {"rlang_env_browse", (r_fn_ptr) &rlang_env_browse, 2}, + {"rlang_env_is_browsed", (r_fn_ptr) &rlang_env_is_browsed, 1}, + {"rlang_ns_registry_env", (r_fn_ptr) &rlang_ns_registry_env, 0}, + {"rlang_hash", (r_fn_ptr) &rlang_hash, 1}, {NULL, NULL, 0} }; extern sexp* rlang_ext_arg_match0(sexp*); +extern sexp* rlang_ext_capturearginfo(sexp*); +extern sexp* rlang_ext_capturedots(sexp*); +extern sexp* rlang_ext_dots_values(sexp*); -extern sexp* rlang_ext2_is_missing(sexp*, sexp*, sexp*, sexp*); extern sexp* rlang_ext2_call2(sexp*, sexp*, sexp*, sexp*); -extern sexp* rlang_ext2_dots_values(sexp*, sexp*, sexp*, sexp*); extern sexp* rlang_ext2_exec(sexp*, sexp*, sexp*, sexp*); +extern sexp* rlang_ext2_eval(sexp*, sexp*, sexp*, sexp*); +extern sexp* rlang_ext2_eval_tidy(sexp*, sexp*, sexp*, sexp*); +extern sexp* rlang_ext2_tilde_eval(sexp*, sexp*, sexp*, sexp*); static const r_external externals[] = { {"rlang_ext_arg_match0", (r_fn_ptr) &rlang_ext_arg_match0, 3}, + {"rlang_ext_capturearginfo", (r_fn_ptr) &rlang_ext_capturearginfo, 2}, + {"rlang_ext_capturedots", (r_fn_ptr) &rlang_ext_capturedots, 1}, + {"rlang_ext_dots_values", (r_fn_ptr) &rlang_ext_dots_values, 7}, - {"rlang_ext2_is_missing", (r_fn_ptr) &rlang_ext2_is_missing, 1}, {"rlang_ext2_call2", (r_fn_ptr) &rlang_ext2_call2, 2}, - {"rlang_ext2_dots_values", (r_fn_ptr) &rlang_ext2_dots_values, 6}, {"rlang_ext2_exec", (r_fn_ptr) &rlang_ext2_exec, 2}, + {"rlang_ext2_eval", (r_fn_ptr) &rlang_ext2_eval, 2}, + {"rlang_ext2_eval_tidy", (r_fn_ptr) &rlang_ext2_eval_tidy, 3}, + {"rlang_ext2_tilde_eval", (r_fn_ptr) &rlang_ext2_tilde_eval, 3}, {NULL, NULL, 0} }; @@ -344,10 +359,10 @@ extern bool is_splice_box(sexp*); extern sexp* rlang_env_dots_values(sexp*); extern sexp* rlang_env_dots_list(sexp*); +extern sexp* rlang_eval_tidy(sexp*, sexp*, sexp*); +extern void rlang_print_backtrace(bool full); export void R_init_rlang(r_dll_info* dll) { - r_register_c_callable("rlang", "rlang_squash_if", (r_fn_ptr) &r_squash_if); - // The quosure functions are stable r_register_c_callable("rlang", "rlang_new_quosure", (r_fn_ptr) &rlang_new_quosure); r_register_c_callable("rlang", "rlang_is_quosure", (r_fn_ptr) &rlang_is_quosure); @@ -370,14 +385,21 @@ r_register_c_callable("rlang", "rlang_env_dots_values", (r_fn_ptr) &rlang_env_dots_values); r_register_c_callable("rlang", "rlang_env_dots_list", (r_fn_ptr) &rlang_env_dots_list); r_register_c_callable("rlang", "rlang_sym_as_character", (r_fn_ptr) &rlang_sym_as_character); + r_register_c_callable("rlang", "rlang_str_as_symbol", (r_fn_ptr) &r_str_as_symbol); // Experimental method for exporting C function pointers as actual R objects rlang_register_pointer("rlang", "rlang_test_is_spliceable", (r_fn_ptr) &rlang_is_clevel_spliceable); + // Experimental + r_register_c_callable("rlang", "rlang_squash_if", (r_fn_ptr) &r_squash_if); + // Compatibility r_register_c_callable("rlang", "rlang_as_data_mask", (r_fn_ptr) &rlang_as_data_mask_compat); r_register_c_callable("rlang", "rlang_new_data_mask", (r_fn_ptr) &rlang_new_data_mask_compat); + // Only for debugging - no stability guaranteed + r_register_c_callable("rlang", "rlang_print_backtrace", (r_fn_ptr) &rlang_print_backtrace); + r_register_r_callables(dll, r_callables, externals); } diff -Nru r-cran-rlang-0.4.8/src/internal/arg.c r-cran-rlang-0.4.10/src/internal/arg.c --- r-cran-rlang-0.4.8/src/internal/arg.c 2020-08-12 09:36:27.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/arg.c 2020-11-19 14:04:11.000000000 +0000 @@ -75,17 +75,6 @@ return quo; } -sexp* rlang_ext2_is_missing(sexp* _call, sexp* _op, sexp* args, sexp* env) { - args = r_node_cdr(args); - - sexp* missing = r_eval(r_node_car(args), env); - if (r_lgl_get(missing, 0)) { - return r_shared_true; - } - - return r_lgl(r_eval(r_syms_x, env) == r_syms_missing); -} - static sexp* stop_arg_match_call = NULL; static sexp* arg_nm_sym = NULL; void arg_match0_abort(const char* msg, sexp* env); diff -Nru r-cran-rlang-0.4.8/src/internal/dots.c r-cran-rlang-0.4.10/src/internal/dots.c --- r-cran-rlang-0.4.8/src/internal/dots.c 2020-08-12 09:34:55.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/dots.c 2020-11-19 16:24:15.000000000 +0000 @@ -254,7 +254,13 @@ case r_type_character: case r_type_raw: case r_type_list: - x = r_vec_coerce(x, r_type_pairlist); + // Check for length because `Rf_coerceVector()` to pairlist fails + // with named empty vectors (#1045) + if (r_length(x)) { + x = r_vec_coerce(x, r_type_pairlist); + } else { + x = r_null; + } break; case r_type_call: if (deep && r_is_symbol(r_node_car(x), "{")) { @@ -860,18 +866,16 @@ return dots; } -sexp* rlang_ext2_dots_values(sexp* call, - sexp* op, - sexp* args, - sexp* env) { +sexp* rlang_ext_dots_values(sexp* args) { args = r_node_cdr(args); - sexp* named = KEEP(r_eval(r_node_car(args), env)); args = r_node_cdr(args); - sexp* ignore_empty = KEEP(r_eval(r_node_car(args), env)); args = r_node_cdr(args); - sexp* preserve_empty = KEEP(r_eval(r_node_car(args), env)); args = r_node_cdr(args); - sexp* unquote_names = KEEP(r_eval(r_node_car(args), env)); args = r_node_cdr(args); - sexp* homonyms = KEEP(r_eval(r_node_car(args), env)); args = r_node_cdr(args); - sexp* check_assign = KEEP(r_eval(r_node_car(args), env)); + sexp* env = r_node_car(args); args = r_node_cdr(args); + sexp* named = r_node_car(args); args = r_node_cdr(args); + sexp* ignore_empty = r_node_car(args); args = r_node_cdr(args); + sexp* preserve_empty = r_node_car(args); args = r_node_cdr(args); + sexp* unquote_names = r_node_car(args); args = r_node_cdr(args); + sexp* homonyms = r_node_car(args); args = r_node_cdr(args); + sexp* check_assign = r_node_car(args); sexp* out = dots_values_impl(env, named, @@ -882,7 +886,6 @@ check_assign, false); - FREE(6); return out; } sexp* rlang_env_dots_values(sexp* env) { diff -Nru r-cran-rlang-0.4.8/src/internal/env-binding.c r-cran-rlang-0.4.10/src/internal/env-binding.c --- r-cran-rlang-0.4.8/src/internal/env-binding.c 2020-08-12 09:35:05.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/env-binding.c 2020-11-19 12:47:54.000000000 +0000 @@ -189,7 +189,7 @@ enum bind_type c_bind_type = parse_bind_type(bind_type); if (r_typeof(values) != r_type_list) { - r_stop_internal_error("rlang_env_bind", "`values` must be a list."); + r_stop_internal("rlang_env_bind", "`values` must be a list."); } r_ssize n = r_length(values); diff -Nru r-cran-rlang-0.4.8/src/internal/eval-tidy.c r-cran-rlang-0.4.10/src/internal/eval-tidy.c --- r-cran-rlang-0.4.8/src/internal/eval-tidy.c 2020-08-12 09:36:11.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/eval-tidy.c 2020-11-23 12:29:10.000000000 +0000 @@ -160,14 +160,14 @@ sexp* data_mask; if (bottom == r_null) { - bottom = KEEP(r_new_environment(r_empty_env, 0)); + bottom = KEEP(r_new_environment(r_empty_env, 100)); data_mask = bottom; } else { check_data_mask_input(bottom, "bottom"); // Create a child because we don't know what might be in `bottom` // and we need to clear its contents without deleting any object // created in the data mask environment - data_mask = KEEP(r_new_environment(bottom, 0)); + data_mask = KEEP(r_new_environment(bottom, 100)); } if (top == r_null) { @@ -221,7 +221,7 @@ FREE(1); } - if (obj != r_syms_unbound && !r_is_function(obj)) { + if (obj != r_syms_unbound) { FREE(n_kept); return obj; } @@ -271,6 +271,7 @@ } static sexp* data_pronoun_sym = NULL; +static r_ssize mask_length(r_ssize n); sexp* rlang_as_data_mask(sexp* data) { if (mask_info(data).type == RLANG_MASK_DATA) { @@ -304,17 +305,21 @@ check_unique_names(data); sexp* names = r_names(data); - bottom = KEEP_N(r_new_environment(r_empty_env, 0), n_protect); + + r_ssize n_mask = mask_length(r_length(data)); + bottom = KEEP_N(r_new_environment(r_empty_env, n_mask), n_protect); if (names != r_null) { r_ssize n = r_length(data); + sexp* const * p_names = r_chr_deref_const(names); + sexp* const * p_data = r_list_deref_const(data); + for (r_ssize i = 0; i < n; ++i) { // Ignore empty or missing names - sexp* nm = r_chr_get(names, i); + sexp* nm = p_names[i]; if (r_str_is_name(nm)) { - sexp* elt = r_list_get(data, i); - r_env_poke(bottom, r_str_as_symbol(nm), elt); + r_env_poke(bottom, r_str_as_symbol(nm), p_data[i]); } } } @@ -335,6 +340,12 @@ return data_mask; } +static +r_ssize mask_length(r_ssize n) { + r_ssize n_grown = r_double_as_ssize(r_double_mult(r_ssize_as_double(n), 1.05)); + return r_ssize_max(n_grown, r_ssize_add(n, 20)); +} + // For compatibility of the exported C callable // TODO: warn sexp* rlang_new_data_mask_compat(sexp* bottom, sexp* top, sexp* parent) { @@ -432,6 +443,14 @@ return r_eval(expr, info.mask); } +sexp* rlang_ext2_tilde_eval(sexp* call, sexp* op, sexp* args, sexp* rho) { + args = r_node_cdr(args); + sexp* tilde = r_node_car(args); args = r_node_cdr(args); + sexp* current_frame = r_node_car(args); args = r_node_cdr(args); + sexp* caller_frame = r_node_car(args); + return rlang_tilde_eval(tilde, current_frame, caller_frame); +} + static const char* data_mask_objects_names[5] = { ".__tidyeval_data_mask__.", "~", ".top_env", ".env", NULL }; @@ -519,13 +538,21 @@ return out; } +sexp* rlang_ext2_eval_tidy(sexp* call, sexp* op, sexp* args, sexp* rho) { + args = r_node_cdr(args); + sexp* expr = r_node_car(args); args = r_node_cdr(args); + sexp* data = r_node_car(args); args = r_node_cdr(args); + sexp* env = r_node_car(args); + return rlang_eval_tidy(expr, data, env); +} + void rlang_init_eval_tidy() { sexp* rlang_ns_env = KEEP(r_ns_env("rlang")); tilde_fn = r_parse_eval( "function(...) { \n" - " .Call(rlang_tilde_eval, \n" + " .External2(rlang_ext2_tilde_eval, \n" " sys.call(), # Quosure env \n" " environment(), # Unwind-protect env \n" " parent.frame() # Lexical env \n" diff -Nru r-cran-rlang-0.4.8/src/internal/hash.c r-cran-rlang-0.4.10/src/internal/hash.c --- r-cran-rlang-0.4.8/src/internal/hash.c 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/hash.c 2020-12-18 09:31:10.000000000 +0000 @@ -0,0 +1,252 @@ +#include + +/* + * Using the standard xxhash defines, as seen in: + * https://github.com/Cyan4973/xxHash/blob/4c881f796d6af27ef7d9c48f87817da0d3d75dc1/xxhash.c#L40-L41 + */ +#define XXH_STATIC_LINKING_ONLY +#define XXH_IMPLEMENTATION + +#include "xxhash/xxhash.h" + +#include // sprintf() +#include // PRIx64 + +/* + * Construct a define specifying whether version 2 or 3 of + * `R_Serialize()` should be used. Version 3 is used with R >= 3.5.0, and + * has support for ALTREP. + */ +#ifdef R_VERSION +# if (R_VERSION >= R_Version(3, 5, 0)) +# define USE_VERSION_3 1 +# else +# define USE_VERSION_3 0 +# endif +#else +# define USE_VERSION_3 0 +#endif + +/* + * Before any R object data is serialized, `R_Serialize()` will first write out: + * + * Serialization info: + * - 2 bytes for `"X\n"` to declare "binary" serialization (i.e. not "ascii") + * - An `int` representing the serialization version + * - An `int` representing `R_VERSION` + * - An `int` representing the minimum R version where this serialization + * version was supported. This is `R_Version(2,3,0)` for version 2, and + * `R_Version(3,5,0)` for version 3. + * + * With version 3, it additionally writes out: + * - An `int` representing the `strlen()` of a `const char*` containing the + * native encoding. + * - A `const char*` for that native encoding. The length of this comes from + * the previous `int` that was written out. + * + * Since this changes between R versions, we skip these first bytes before + * streaming any data into the hashing algorithm. + * + * Reference to show where R appends this information: + * https://github.com/wch/r-source/blob/d48ecd61012fa6ae645d087d9a6e97e200c32fbc/src/main/serialize.c#L1382-L1389 + */ +#define N_BYTES_SERIALIZATION_INFO (2 + 3 * sizeof(int)) + +#if USE_VERSION_3 +# define N_BYTES_N_NATIVE_ENC (sizeof(int)) +#endif + +// ----------------------------------------------------------------------------- + +struct exec_data { + sexp* x; + XXH3_state_t* p_xx_state; +}; + +static sexp* hash_impl(void* p_data); +static void hash_cleanup(void* p_data); + +sexp* rlang_hash(sexp* x) { + XXH3_state_t* p_xx_state = XXH3_createState(); + + struct exec_data data = { + .x = x, + .p_xx_state = p_xx_state + }; + + return R_ExecWithCleanup(hash_impl, &data, hash_cleanup, &data); +} + +struct hash_state_t { + bool skip; + int n_skipped; +#if USE_VERSION_3 + int n_native_enc; +#endif + XXH3_state_t* p_xx_state; +}; + +static inline struct hash_state_t new_hash_state(XXH3_state_t* p_xx_state); +static inline int hash_version(); +static inline void hash_bytes(R_outpstream_t stream, void* p_input, int n); +static inline void hash_char(R_outpstream_t stream, int input); + +static +sexp* hash_impl(void* p_data) { + struct exec_data* p_exec_data = (struct exec_data*) p_data; + sexp* x = p_exec_data->x; + XXH3_state_t* p_xx_state = p_exec_data->p_xx_state; + + XXH_errorcode err = XXH3_128bits_reset(p_xx_state); + if (err == XXH_ERROR) { + r_abort("Couldn't initialize hash state."); + } + + struct hash_state_t state = new_hash_state(p_xx_state); + + int version = hash_version(); + + // Unused + sexp* (*hook)(sexp*, sexp*) = NULL; + sexp* hook_data = r_null; + + // We use the unstructured binary format, rather than XDR, as that is faster. + // In theory it may result in different hashes on different platforms, but + // in practice only integers can have variable width and here they are 32 bit. + R_pstream_format_t format = R_pstream_binary_format; + + struct R_outpstream_st stream; + + R_InitOutPStream( + &stream, + (R_pstream_data_t) &state, + format, + version, + hash_char, + hash_bytes, + hook, + hook_data + ); + + R_Serialize(x, &stream); + + XXH128_hash_t hash = XXH3_128bits_digest(p_xx_state); + + // R assumes C99, so these are always defined as `uint64_t` in xxhash.h + XXH64_hash_t high = hash.high64; + XXH64_hash_t low = hash.low64; + + // 32 for hash, 1 for terminating null added by `sprintf()` + char out[32 + 1]; + + sprintf(out, "%016" PRIx64 "%016" PRIx64, high, low); + + return r_chr(out); +} + +static +void hash_cleanup(void* p_data) { + struct exec_data* p_exec_data = (struct exec_data*) p_data; + XXH3_state_t* p_xx_state = p_exec_data->p_xx_state; + XXH3_freeState(p_xx_state); +} + +static inline +struct hash_state_t new_hash_state(XXH3_state_t* p_xx_state) { + return (struct hash_state_t) { + .skip = true, + .n_skipped = 0, +#if USE_VERSION_3 + .n_native_enc = 0, +#endif + .p_xx_state = p_xx_state + }; +} + +static inline +int hash_version() { +#if USE_VERSION_3 + return 3; +#else + return 2; +#endif +} + +static inline void hash_skip(struct hash_state_t* p_state, void* p_input, int n); + +static inline +void hash_bytes(R_outpstream_t stream, void* p_input, int n) { + struct hash_state_t* p_state = (struct hash_state_t*) stream->data; + + if (p_state->skip) { + hash_skip(p_state, p_input, n); + return; + } + + XXH3_state_t* p_xx_state = p_state->p_xx_state; + XXH_errorcode err = XXH3_128bits_update(p_xx_state, p_input, n); + + if (err == XXH_ERROR) { + r_abort("Couldn't update hash state."); + } +} + +static inline +void hash_char(R_outpstream_t stream, int input) { + // Despite the confusing signature, which is required by `R_Serialize()`, + // `input` is always a `char` so this conversion is safe + unsigned char byte = (unsigned char) input; + unsigned char* p_byte = &byte; + hash_bytes(stream, p_byte, 1); +} + +#if USE_VERSION_3 + +static inline +void hash_skip(struct hash_state_t* p_state, void* p_input, int n) { + if (p_state->n_skipped < N_BYTES_SERIALIZATION_INFO) { + // Skip serialization info bytes + p_state->n_skipped += n; + return; + } + + if (p_state->n_skipped == N_BYTES_SERIALIZATION_INFO) { + // We've skipped all serialization info bytes. + // Incoming bytes tell the size of the native encoding string. + int* p_x = (int*) p_input; + p_state->n_native_enc = *p_x; + + p_state->n_skipped += n; + + return; + } + + p_state->n_skipped += n; + + int n_bytes_header = + N_BYTES_SERIALIZATION_INFO + + N_BYTES_N_NATIVE_ENC + + p_state->n_native_enc; + + if (p_state->n_skipped == n_bytes_header) { + // We've skipped all serialization header bytes at this point + p_state->skip = false; + } +} + +#else // !USE_VERSION_3 + +static inline +void hash_skip(struct hash_state_t* p_state, void* p_input, int n) { + // Skip serialization header bytes + p_state->n_skipped += n; + + if (p_state->n_skipped == N_BYTES_SERIALIZATION_INFO) { + // We've skipped all serialization header bytes at this point + p_state->skip = false; + } +} + +#endif // USE_VERSION_3 + +#undef USE_VERSION_3 diff -Nru r-cran-rlang-0.4.8/src/internal/nse-defuse.c r-cran-rlang-0.4.10/src/internal/nse-defuse.c --- r-cran-rlang-0.4.8/src/internal/nse-defuse.c 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/nse-defuse.c 2020-11-19 16:45:08.000000000 +0000 @@ -0,0 +1,17 @@ +#include +#include "utils.h" + +// Defined in capture.c +sexp* rlang_capturearginfo(sexp* call, sexp* op, sexp* args, sexp* rho); +sexp* rlang_capturedots(sexp* call, sexp* op, sexp* args, sexp* rho); + +sexp* rlang_ext_capturearginfo(sexp* args) { + args = r_node_cdr(args); + sexp* env = r_node_car(args); args = r_node_cdr(args); + return rlang_capturearginfo(r_null, r_null, args, env); +} + +sexp* rlang_ext_capturedots(sexp* args) { + args = r_node_cdr(args); + return rlang_capturedots(r_null, r_null, args, r_base_env); +} diff -Nru r-cran-rlang-0.4.8/src/internal/utils.c r-cran-rlang-0.4.10/src/internal/utils.c --- r-cran-rlang-0.4.8/src/internal/utils.c 2020-06-26 13:10:13.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/utils.c 2020-11-23 12:29:10.000000000 +0000 @@ -20,4 +20,32 @@ } } + +/* For debugging with gdb or lldb. Exported as a C callable. + * Usage with lldb: + * + * ``` + * // Full backtrace: + * expr R_GetCCallable("rlang", "rlang_print_backtrace")(true) + * + * // Linear backtrace: + * expr R_GetCCallable("rlang", "rlang_print_backtrace")(false) + * ``` + */ +void rlang_print_backtrace(bool full) { + sexp* env = KEEP(r_current_frame()); + sexp* trace = KEEP(r_parse_eval("rlang::trace_back()", env)); + + const char* source = full ? + "print(x, simplify = 'none')" : + "print(x, simplify = 'branch')"; + sexp* call = KEEP(r_parse(source)); + + r_eval_with_x(call, r_base_env, trace); + + FREE(3); + return; +} + + void rlang_init_utils() { } diff -Nru r-cran-rlang-0.4.8/src/internal/utils.h r-cran-rlang-0.4.10/src/internal/utils.h --- r-cran-rlang-0.4.8/src/internal/utils.h 2020-07-08 19:08:49.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/utils.h 2020-11-19 16:15:48.000000000 +0000 @@ -9,7 +9,8 @@ extern sexp* rlang_ns_env; - __attribute__((noreturn)) +__attribute__((noreturn)) +static inline void never_reached(const char* fn) { r_abort("Internal error in `%s()`: Reached the unreachable.", fn); } diff -Nru r-cran-rlang-0.4.8/src/internal/xxhash/xxhash.h r-cran-rlang-0.4.10/src/internal/xxhash/xxhash.h --- r-cran-rlang-0.4.8/src/internal/xxhash/xxhash.h 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal/xxhash/xxhash.h 2020-12-18 09:31:10.000000000 +0000 @@ -0,0 +1,4766 @@ +/* + * xxHash - Extremely Fast Hash algorithm + * Header File + * Copyright (C) 2012-2020 Yann Collet + * + * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at: + * - xxHash homepage: https://www.xxhash.com + * - xxHash source repository: https://github.com/Cyan4973/xxHash + */ + +/* TODO: update */ +/* Notice extracted from xxHash homepage: + +xxHash is an extremely fast hash algorithm, running at RAM speed limits. +It also successfully passes all tests from the SMHasher suite. + +Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) + +Name Speed Q.Score Author +xxHash 5.4 GB/s 10 +CrapWow 3.2 GB/s 2 Andrew +MumurHash 3a 2.7 GB/s 10 Austin Appleby +SpookyHash 2.0 GB/s 10 Bob Jenkins +SBox 1.4 GB/s 9 Bret Mulvey +Lookup3 1.2 GB/s 9 Bob Jenkins +SuperFastHash 1.2 GB/s 1 Paul Hsieh +CityHash64 1.05 GB/s 10 Pike & Alakuijala +FNV 0.55 GB/s 5 Fowler, Noll, Vo +CRC32 0.43 GB/s 9 +MD5-32 0.33 GB/s 10 Ronald L. Rivest +SHA1-32 0.28 GB/s 10 + +Q.Score is a measure of quality of the hash function. +It depends on successfully passing SMHasher test set. +10 is a perfect score. + +Note: SMHasher's CRC32 implementation is not the fastest one. +Other speed-oriented implementations can be faster, +especially in combination with PCLMUL instruction: +https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735 + +A 64-bit version, named XXH64, is available since r35. +It offers much better speed, but for 64-bit applications only. +Name Speed on 64 bits Speed on 32 bits +XXH64 13.8 GB/s 1.9 GB/s +XXH32 6.8 GB/s 6.0 GB/s +*/ + +#if defined (__cplusplus) +extern "C" { +#endif + +/* **************************** + * INLINE mode + ******************************/ +/*! + * XXH_INLINE_ALL (and XXH_PRIVATE_API) + * Use these build macros to inline xxhash into the target unit. + * Inlining improves performance on small inputs, especially when the length is + * expressed as a compile-time constant: + * + * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html + * + * It also keeps xxHash symbols private to the unit, so they are not exported. + * + * Usage: + * #define XXH_INLINE_ALL + * #include "xxhash.h" + * + * Do not compile and link xxhash.o as a separate object, as it is not useful. + */ +#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ + && !defined(XXH_INLINE_ALL_31684351384) + /* this section should be traversed only once */ +# define XXH_INLINE_ALL_31684351384 + /* give access to the advanced API, required to compile implementations */ +# undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ +# define XXH_STATIC_LINKING_ONLY + /* make all functions private */ +# undef XXH_PUBLIC_API +# if defined(__GNUC__) +# define XXH_PUBLIC_API static __inline __attribute__((unused)) +# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define XXH_PUBLIC_API static inline +# elif defined(_MSC_VER) +# define XXH_PUBLIC_API static __inline +# else + /* note: this version may generate warnings for unused static functions */ +# define XXH_PUBLIC_API static +# endif + + /* + * This part deals with the special case where a unit wants to inline xxHash, + * but "xxhash.h" has previously been included without XXH_INLINE_ALL, such + * as part of some previously included *.h header file. + * Without further action, the new include would just be ignored, + * and functions would effectively _not_ be inlined (silent failure). + * The following macros solve this situation by prefixing all inlined names, + * avoiding naming collision with previous inclusions. + */ +# ifdef XXH_NAMESPACE +# error "XXH_INLINE_ALL with XXH_NAMESPACE is not supported" + /* + * Note: Alternative: #undef all symbols (it's a pretty large list). + * Without #error: it compiles, but functions are actually not inlined. + */ +# endif +# define XXH_NAMESPACE XXH_INLINE_ + /* + * Some identifiers (enums, type names) are not symbols, but they must + * still be renamed to avoid redeclaration. + * Alternative solution: do not redeclare them. + * However, this requires some #ifdefs, and is a more dispersed action. + * Meanwhile, renaming can be achieved in a single block + */ +# define XXH_IPREF(Id) XXH_INLINE_ ## Id +# define XXH_OK XXH_IPREF(XXH_OK) +# define XXH_ERROR XXH_IPREF(XXH_ERROR) +# define XXH_errorcode XXH_IPREF(XXH_errorcode) +# define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) +# define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) +# define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) +# define XXH32_state_s XXH_IPREF(XXH32_state_s) +# define XXH32_state_t XXH_IPREF(XXH32_state_t) +# define XXH64_state_s XXH_IPREF(XXH64_state_s) +# define XXH64_state_t XXH_IPREF(XXH64_state_t) +# define XXH3_state_s XXH_IPREF(XXH3_state_s) +# define XXH3_state_t XXH_IPREF(XXH3_state_t) +# define XXH128_hash_t XXH_IPREF(XXH128_hash_t) + /* Ensure the header is parsed again, even if it was previously included */ +# undef XXHASH_H_5627135585666179 +# undef XXHASH_H_STATIC_13879238742 +#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ + + + +/* **************************************************************** + * Stable API + *****************************************************************/ +#ifndef XXHASH_H_5627135585666179 +#define XXHASH_H_5627135585666179 1 + +/* specific declaration modes for Windows */ +#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) +# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) +# ifdef XXH_EXPORT +# define XXH_PUBLIC_API __declspec(dllexport) +# elif XXH_IMPORT +# define XXH_PUBLIC_API __declspec(dllimport) +# endif +# else +# define XXH_PUBLIC_API /* do nothing */ +# endif +#endif + +/*! + * XXH_NAMESPACE, aka Namespace Emulation: + * + * If you want to include _and expose_ xxHash functions from within your own + * library, but also want to avoid symbol collisions with other libraries which + * may also include xxHash, you can use XXH_NAMESPACE to automatically prefix + * any public symbol from xxhash library with the value of XXH_NAMESPACE + * (therefore, avoid empty or numeric values). + * + * Note that no change is required within the calling program as long as it + * includes `xxhash.h`: Regular symbol names will be automatically translated + * by this header. + */ +#ifdef XXH_NAMESPACE +# define XXH_CAT(A,B) A##B +# define XXH_NAME2(A,B) XXH_CAT(A,B) +# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) +/* XXH32 */ +# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) +# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) +# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) +# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) +# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) +# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) +# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) +# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) +# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) +/* XXH64 */ +# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) +# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) +# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) +# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) +# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) +# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) +# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) +# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) +# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) +/* XXH3_64bits */ +# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) +# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) +# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) +# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) +# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) +# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) +# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) +# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) +# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) +# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) +# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) +# define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) +/* XXH3_128bits */ +# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) +# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) +# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) +# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) +# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) +# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) +# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) +# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) +# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) +# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) +# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) +# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) +# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) +#endif + + +/* ************************************* +* Version +***************************************/ +#define XXH_VERSION_MAJOR 0 +#define XXH_VERSION_MINOR 8 +#define XXH_VERSION_RELEASE 0 +#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) +XXH_PUBLIC_API unsigned XXH_versionNumber (void); + + +/* **************************** +* Definitions +******************************/ +#include /* size_t */ +typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; + + +/*-********************************************************************** +* 32-bit hash +************************************************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint32_t XXH32_hash_t; +#else +# include +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int XXH32_hash_t; +# else +# if ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long XXH32_hash_t; +# else +# error "unsupported platform: need a 32-bit type" +# endif +# endif +#endif + +/*! + * XXH32(): + * Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input". + * The memory between input & input+length must be valid (allocated and read-accessible). + * "seed" can be used to alter the result predictably. + * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s + * + * Note: XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. It provides a superior level of + * dispersion, and greatly reduces the risks of collisions. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); + +/******* Streaming *******/ + +/* + * Streaming functions generate the xxHash value from an incrememtal input. + * This method is slower than single-call functions, due to state management. + * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. + * + * An XXH state must first be allocated using `XXH*_createState()`. + * + * Start a new hash by initializing the state with a seed using `XXH*_reset()`. + * + * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. + * + * The function returns an error code, with 0 meaning OK, and any other value + * meaning there is an error. + * + * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. + * This function returns the nn-bits hash as an int or long long. + * + * It's still possible to continue inserting input into the hash state after a + * digest, and generate new hash values later on by invoking `XXH*_digest()`. + * + * When done, release the state using `XXH*_freeState()`. + */ + +typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); + +XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); + +/******* Canonical representation *******/ + +/* + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * This the simplest and fastest format for further post-processing. + * + * However, this leaves open the question of what is the order on the byte level, + * since little and big endian conventions will store the same number differently. + * + * The canonical representation settles this issue by mandating big-endian + * convention, the same convention as human-readable numbers (large digits first). + * + * When writing hash values to storage, sending them over a network, or printing + * them, it's highly recommended to use the canonical representation to ensure + * portability across a wider range of systems, present and future. + * + * The following functions allow transformation of hash values to and from + * canonical format. + */ + +typedef struct { unsigned char digest[4]; } XXH32_canonical_t; +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); + + +#ifndef XXH_NO_LONG_LONG +/*-********************************************************************** +* 64-bit hash +************************************************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint64_t XXH64_hash_t; +#else + /* the following type must have a width of 64-bit */ + typedef unsigned long long XXH64_hash_t; +#endif + +/*! + * XXH64(): + * Returns the 64-bit hash of sequence of length @length stored at memory + * address @input. + * @seed can be used to alter the result predictably. + * + * This function usually runs faster on 64-bit systems, but slower on 32-bit + * systems (see benchmark). + * + * Note: XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. It provides a superior level of + * dispersion, and greatly reduces the risks of collisions. + */ +XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, XXH64_hash_t seed); + +/******* Streaming *******/ +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state); + +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); + + +/*-********************************************************************** +* XXH3 64-bit variant +************************************************************************/ + +/* ************************************************************************ + * XXH3 is a new hash algorithm featuring: + * - Improved speed for both small and large inputs + * - True 64-bit and 128-bit outputs + * - SIMD acceleration + * - Improved 32-bit viability + * + * Speed analysis methodology is explained here: + * + * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html + * + * In general, expect XXH3 to run about ~2x faster on large inputs and >3x + * faster on small ones compared to XXH64, though exact differences depend on + * the platform. + * + * The algorithm is portable: Like XXH32 and XXH64, it generates the same hash + * on all platforms. + * + * It benefits greatly from SIMD and 64-bit arithmetic, but does not require it. + * + * Almost all 32-bit and 64-bit targets that can run XXH32 smoothly can run + * XXH3 at competitive speeds, even if XXH64 runs slowly. Further details are + * explained in the implementation. + * + * Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8, + * ZVector and scalar targets. This can be controlled with the XXH_VECTOR macro. + * + * XXH3 offers 2 variants, _64bits and _128bits. + * When only 64 bits are needed, prefer calling the _64bits variant, as it + * reduces the amount of mixing, resulting in faster speed on small inputs. + * + * It's also generally simpler to manipulate a scalar return type than a struct. + * + * The 128-bit version adds additional strength, but it is slightly slower. + * + * The XXH3 algorithm is still in development. + * The results it produces may still change in future versions. + * + * Results produced by v0.7.x are not comparable with results from v0.7.y. + * However, the API is completely stable, and it can safely be used for + * ephemeral data (local sessions). + * + * Avoid storing values in long-term storage until the algorithm is finalized. + * XXH3's return values will be officially finalized upon reaching v0.8.0. + * + * After which, return values of XXH3 and XXH128 will no longer change in + * future versions. + * + * The API supports one-shot hashing, streaming mode, and custom secrets. + */ + +/* XXH3_64bits(): + * default 64-bit variant, using default secret and default seed of 0. + * It's the fastest variant. */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len); + +/* + * XXH3_64bits_withSeed(): + * This variant generates a custom secret on the fly + * based on default secret altered using the `seed` value. + * While this operation is decently fast, note that it's not completely free. + * Note: seed==0 produces the same results as XXH3_64bits(). + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); + +/* + * XXH3_64bits_withSecret(): + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN). + * However, the quality of produced hash values depends on secret's entropy. + * Technically, the secret must look like a bunch of random bytes. + * Avoid "trivial" or structured data such as repeated sequences or a text document. + * Whenever unsure about the "randomness" of the blob of bytes, + * consider relabelling it as a "custom seed" instead, + * and employ "XXH3_generateSecret()" (see below) + * to generate a high entropy secret derived from the custom seed. + */ +#define XXH3_SECRET_SIZE_MIN 136 +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + */ +typedef struct XXH3_state_s XXH3_state_t; +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); +XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state); + +/* + * XXH3_64bits_reset(): + * Initialize with default parameters. + * digest will be equivalent to `XXH3_64bits()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr); +/* + * XXH3_64bits_reset_withSeed(): + * Generate a custom secret from `seed`, and store it into `statePtr`. + * digest will be equivalent to `XXH3_64bits_withSeed()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +/* + * XXH3_64bits_reset_withSecret(): + * `secret` is referenced, it _must outlive_ the hash streaming session. + * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, + * and the quality of produced hash values depends on secret's entropy + * (secret's content should look like a bunch of random bytes). + * When in doubt about the randomness of a candidate `secret`, + * consider employing `XXH3_generateSecret()` instead (see below). + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* statePtr); + +/* note : canonical representation of XXH3 is the same as XXH64 + * since they both produce XXH64_hash_t values */ + + +/*-********************************************************************** +* XXH3 128-bit variant +************************************************************************/ + +typedef struct { + XXH64_hash_t low64; + XXH64_hash_t high64; +} XXH128_hash_t; + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + * + * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). + * Use already declared XXH3_createState() and XXH3_freeState(). + * + * All reset and streaming functions have same meaning as their 64-bit counterpart. + */ + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr); + +/* Following helper functions make it possible to compare XXH128_hast_t values. + * Since XXH128_hash_t is a structure, this capability is not offered by the language. + * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ + +/*! + * XXH128_isEqual(): + * Return: 1 if `h1` and `h2` are equal, 0 if they are not. + */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); + +/*! + * XXH128_cmp(): + * + * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. + * + * return: >0 if *h128_1 > *h128_2 + * =0 if *h128_1 == *h128_2 + * <0 if *h128_1 < *h128_2 + */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2); + + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; +XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); +XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src); + + +#endif /* XXH_NO_LONG_LONG */ + +#endif /* XXHASH_H_5627135585666179 */ + + + +#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) +#define XXHASH_H_STATIC_13879238742 +/* **************************************************************************** + * This section contains declarations which are not guaranteed to remain stable. + * They may change in future versions, becoming incompatible with a different + * version of the library. + * These declarations should only be used with static linking. + * Never use them in association with dynamic linking! + ***************************************************************************** */ + +/* + * These definitions are only present to allow static allocation + * of XXH states, on stack or in a struct, for example. + * Never **ever** access their members directly. + */ + +struct XXH32_state_s { + XXH32_hash_t total_len_32; + XXH32_hash_t large_len; + XXH32_hash_t v1; + XXH32_hash_t v2; + XXH32_hash_t v3; + XXH32_hash_t v4; + XXH32_hash_t mem32[4]; + XXH32_hash_t memsize; + XXH32_hash_t reserved; /* never read nor write, might be removed in a future version */ +}; /* typedef'd to XXH32_state_t */ + + +#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ + +struct XXH64_state_s { + XXH64_hash_t total_len; + XXH64_hash_t v1; + XXH64_hash_t v2; + XXH64_hash_t v3; + XXH64_hash_t v4; + XXH64_hash_t mem64[4]; + XXH32_hash_t memsize; + XXH32_hash_t reserved32; /* required for padding anyway */ + XXH64_hash_t reserved64; /* never read nor write, might be removed in a future version */ +}; /* typedef'd to XXH64_state_t */ + +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11+ */ +# include +# define XXH_ALIGN(n) alignas(n) +#elif defined(__GNUC__) +# define XXH_ALIGN(n) __attribute__ ((aligned(n))) +#elif defined(_MSC_VER) +# define XXH_ALIGN(n) __declspec(align(n)) +#else +# define XXH_ALIGN(n) /* disabled */ +#endif + +/* Old GCC versions only accept the attribute after the type in structures. */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ + && defined(__GNUC__) +# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) +#else +# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type +#endif + +#define XXH3_INTERNALBUFFER_SIZE 256 +#define XXH3_SECRET_DEFAULT_SIZE 192 +struct XXH3_state_s { + XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); + /* used to store a custom secret generated from a seed */ + XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); + XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); + XXH32_hash_t bufferedSize; + XXH32_hash_t reserved32; + size_t nbStripesSoFar; + XXH64_hash_t totalLen; + size_t nbStripesPerBlock; + size_t secretLimit; + XXH64_hash_t seed; + XXH64_hash_t reserved64; + const unsigned char* extSecret; /* reference to external secret; + * if == NULL, use .customSecret instead */ + /* note: there may be some padding at the end due to alignment on 64 bytes */ +}; /* typedef'd to XXH3_state_t */ + +#undef XXH_ALIGN_MEMBER + +/* When the XXH3_state_t structure is merely emplaced on stack, + * it should be initialized with XXH3_INITSTATE() or a memset() + * in case its first reset uses XXH3_NNbits_reset_withSeed(). + * This init can be omitted if the first reset uses default or _withSecret mode. + * This operation isn't necessary when the state is created with XXH3_createState(). + * Note that this doesn't prepare the state for a streaming operation, + * it's still necessary to use XXH3_NNbits_reset*() afterwards. + */ +#define XXH3_INITSTATE(XXH3_state_ptr) { (XXH3_state_ptr)->seed = 0; } + + +/* === Experimental API === */ +/* Symbols defined below must be considered tied to a specific library version. */ + +/* + * XXH3_generateSecret(): + * + * Derive a high-entropy secret from any user-defined content, named customSeed. + * The generated secret can be used in combination with `*_withSecret()` functions. + * The `_withSecret()` variants are useful to provide a higher level of protection than 64-bit seed, + * as it becomes much more difficult for an external actor to guess how to impact the calculation logic. + * + * The function accepts as input a custom seed of any length and any content, + * and derives from it a high-entropy secret of length XXH3_SECRET_DEFAULT_SIZE + * into an already allocated buffer secretBuffer. + * The generated secret is _always_ XXH_SECRET_DEFAULT_SIZE bytes long. + * + * The generated secret can then be used with any `*_withSecret()` variant. + * Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`, + * `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()` + * are part of this list. They all accept a `secret` parameter + * which must be very long for implementation reasons (>= XXH3_SECRET_SIZE_MIN) + * _and_ feature very high entropy (consist of random-looking bytes). + * These conditions can be a high bar to meet, so + * this function can be used to generate a secret of proper quality. + * + * customSeed can be anything. It can have any size, even small ones, + * and its content can be anything, even stupidly "low entropy" source such as a bunch of zeroes. + * The resulting `secret` will nonetheless provide all expected qualities. + * + * Supplying NULL as the customSeed copies the default secret into `secretBuffer`. + * When customSeedSize > 0, supplying NULL as customSeed is undefined behavior. + */ +XXH_PUBLIC_API void XXH3_generateSecret(void* secretBuffer, const void* customSeed, size_t customSeedSize); + + +/* simple short-cut to pre-selected XXH3_128bits variant */ +XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); + + +#endif /* XXH_NO_LONG_LONG */ + + +#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) +# define XXH_IMPLEMENTATION +#endif + +#endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ + + +/* ======================================================================== */ +/* ======================================================================== */ +/* ======================================================================== */ + + +/*-********************************************************************** + * xxHash implementation + *-********************************************************************** + * xxHash's implementation used to be hosted inside xxhash.c. + * + * However, inlining requires implementation to be visible to the compiler, + * hence be included alongside the header. + * Previously, implementation was hosted inside xxhash.c, + * which was then #included when inlining was activated. + * This construction created issues with a few build and install systems, + * as it required xxhash.c to be stored in /include directory. + * + * xxHash implementation is now directly integrated within xxhash.h. + * As a consequence, xxhash.c is no longer needed in /include. + * + * xxhash.c is still available and is still useful. + * In a "normal" setup, when xxhash is not inlined, + * xxhash.h only exposes the prototypes and public symbols, + * while xxhash.c can be built into an object file xxhash.o + * which can then be linked into the final binary. + ************************************************************************/ + +#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ + || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) +# define XXH_IMPLEM_13a8737387 + +/* ************************************* +* Tuning parameters +***************************************/ +/*! + * XXH_FORCE_MEMORY_ACCESS: + * By default, access to unaligned memory is controlled by `memcpy()`, which is + * safe and portable. + * + * Unfortunately, on some target/compiler combinations, the generated assembly + * is sub-optimal. + * + * The below switch allow selection of a different access method + * in the search for improved performance. + * Method 0 (default): + * Use `memcpy()`. Safe and portable. Default. + * Method 1: + * `__attribute__((packed))` statement. It depends on compiler extensions + * and is therefore not portable. + * This method is safe if your compiler supports it, and *generally* as + * fast or faster than `memcpy`. + * Method 2: + * Direct access via cast. This method doesn't depend on the compiler but + * violates the C standard. + * It can generate buggy code on targets which do not support unaligned + * memory accesses. + * But in some circumstances, it's the only known way to get the most + * performance (example: GCC + ARMv6) + * Method 3: + * Byteshift. This can generate the best code on old compilers which don't + * inline small `memcpy()` calls, and it might also be faster on big-endian + * systems which lack a native byteswap instruction. + * See https://stackoverflow.com/a/32095106/646947 for details. + * Prefer these methods in priority order (0 > 1 > 2 > 3) + */ +#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if !defined(__clang__) && defined(__GNUC__) && defined(__ARM_FEATURE_UNALIGNED) && defined(__ARM_ARCH) && (__ARM_ARCH == 6) +# define XXH_FORCE_MEMORY_ACCESS 2 +# elif !defined(__clang__) && ((defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ + (defined(__GNUC__) && (defined(__ARM_ARCH) && __ARM_ARCH >= 7))) +# define XXH_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +/*! + * XXH_ACCEPT_NULL_INPUT_POINTER: + * If the input pointer is NULL, xxHash's default behavior is to dereference it, + * triggering a segfault. + * When this macro is enabled, xxHash actively checks the input for a null pointer. + * If it is, the result for null input pointers is the same as a zero-length input. + */ +#ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */ +# define XXH_ACCEPT_NULL_INPUT_POINTER 0 +#endif + +/*! + * XXH_FORCE_ALIGN_CHECK: + * This is an important performance trick + * for architectures without decent unaligned memory access performance. + * It checks for input alignment, and when conditions are met, + * uses a "fast path" employing direct 32-bit/64-bit read, + * resulting in _dramatically faster_ read speed. + * + * The check costs one initial branch per hash, which is generally negligible, but not zero. + * Moreover, it's not useful to generate binary for an additional code path + * if memory access uses same instruction for both aligned and unaligned adresses. + * + * In these cases, the alignment check can be removed by setting this macro to 0. + * Then the code will always use unaligned memory access. + * Align check is automatically disabled on x86, x64 & arm64, + * which are platforms known to offer good unaligned memory accesses performance. + * + * This option does not affect XXH3 (only XXH32 and XXH64). + */ +#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ +# if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \ + || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */ +# define XXH_FORCE_ALIGN_CHECK 0 +# else +# define XXH_FORCE_ALIGN_CHECK 1 +# endif +#endif + +/*! + * XXH_NO_INLINE_HINTS: + * + * By default, xxHash tries to force the compiler to inline almost all internal + * functions. + * + * This can usually improve performance due to reduced jumping and improved + * constant folding, but significantly increases the size of the binary which + * might not be favorable. + * + * Additionally, sometimes the forced inlining can be detrimental to performance, + * depending on the architecture. + * + * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the + * compiler full control on whether to inline or not. + * + * When not optimizing (-O0), optimizing for size (-Os, -Oz), or using + * -fno-inline with GCC or Clang, this will automatically be defined. + */ +#ifndef XXH_NO_INLINE_HINTS +# if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \ + || defined(__NO_INLINE__) /* -O0, -fno-inline */ +# define XXH_NO_INLINE_HINTS 1 +# else +# define XXH_NO_INLINE_HINTS 0 +# endif +#endif + +/*! + * XXH_REROLL: + * Whether to reroll XXH32_finalize, and XXH64_finalize, + * instead of using an unrolled jump table/if statement loop. + * + * This is automatically defined on -Os/-Oz on GCC and Clang. + */ +#ifndef XXH_REROLL +# if defined(__OPTIMIZE_SIZE__) +# define XXH_REROLL 1 +# else +# define XXH_REROLL 0 +# endif +#endif + + +/* ************************************* +* Includes & Memory related functions +***************************************/ +/*! + * Modify the local functions below should you wish to use + * different memory routines for malloc() and free() + */ +#include + +static void* XXH_malloc(size_t s) { return malloc(s); } +static void XXH_free(void* p) { free(p); } + +/*! and for memcpy() */ +#include +static void* XXH_memcpy(void* dest, const void* src, size_t size) +{ + return memcpy(dest,src,size); +} + +#include /* ULLONG_MAX */ + + +/* ************************************* +* Compiler Specific Options +***************************************/ +#ifdef _MSC_VER /* Visual Studio warning fix */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +#if XXH_NO_INLINE_HINTS /* disable inlining hints */ +# if defined(__GNUC__) +# define XXH_FORCE_INLINE static __attribute__((unused)) +# else +# define XXH_FORCE_INLINE static +# endif +# define XXH_NO_INLINE static +/* enable inlining hints */ +#elif defined(_MSC_VER) /* Visual Studio */ +# define XXH_FORCE_INLINE static __forceinline +# define XXH_NO_INLINE static __declspec(noinline) +#elif defined(__GNUC__) +# define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) +# define XXH_NO_INLINE static __attribute__((noinline)) +#elif defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ +# define XXH_FORCE_INLINE static inline +# define XXH_NO_INLINE static +#else +# define XXH_FORCE_INLINE static +# define XXH_NO_INLINE static +#endif + + + +/* ************************************* +* Debug +***************************************/ +/* + * XXH_DEBUGLEVEL is expected to be defined externally, typically via the + * compiler's command line options. The value must be a number. + */ +#ifndef XXH_DEBUGLEVEL +# ifdef DEBUGLEVEL /* backwards compat */ +# define XXH_DEBUGLEVEL DEBUGLEVEL +# else +# define XXH_DEBUGLEVEL 0 +# endif +#endif + +#if (XXH_DEBUGLEVEL>=1) +# include /* note: can still be disabled with NDEBUG */ +# define XXH_ASSERT(c) assert(c) +#else +# define XXH_ASSERT(c) ((void)0) +#endif + +/* note: use after variable declarations */ +#define XXH_STATIC_ASSERT(c) do { enum { XXH_sa = 1/(int)(!!(c)) }; } while (0) + + +/* ************************************* +* Basic Types +***************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint8_t xxh_u8; +#else + typedef unsigned char xxh_u8; +#endif +typedef XXH32_hash_t xxh_u32; + +#ifdef XXH_OLD_NAMES +# define BYTE xxh_u8 +# define U8 xxh_u8 +# define U32 xxh_u32 +#endif + +/* *** Memory access *** */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE32 and XXH_readBE32. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* + * Force direct memory access. Only works on CPU which support unaligned memory + * access in hardware. + */ +static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; +#endif +static xxh_u32 XXH_read32(const void* ptr) +{ + typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign; + return ((const xxh_unalign*)ptr)->u32; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: https://stackoverflow.com/a/32095106/646947 + */ +static xxh_u32 XXH_read32(const void* memPtr) +{ + xxh_u32 val; + memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + + +/* *** Endianess *** */ +typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; + +/*! + * XXH_CPU_LITTLE_ENDIAN: + * Defined to 1 if the target is little endian, or 0 if it is big endian. + * It can be defined externally, for example on the compiler command line. + * + * If it is not defined, a runtime check (which is usually constant folded) + * is used instead. + */ +#ifndef XXH_CPU_LITTLE_ENDIAN +/* + * Try to detect endianness automatically, to avoid the nonstandard behavior + * in `XXH_isLittleEndian()` + */ +# if defined(_WIN32) /* Windows is always little endian */ \ + || defined(__LITTLE_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 1 +# elif defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 0 +# else +/* + * runtime test, presumed to simplify to a constant by compiler + */ +static int XXH_isLittleEndian(void) +{ + /* + * Portable and well-defined behavior. + * Don't use static: it is detrimental to performance. + */ + const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; + return one.c[0]; +} +# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() +# endif +#endif + + + + +/* **************************************** +* Compiler-specific Functions and Macros +******************************************/ +#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#ifdef __has_builtin +# define XXH_HAS_BUILTIN(x) __has_builtin(x) +#else +# define XXH_HAS_BUILTIN(x) 0 +#endif + +#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ + && XXH_HAS_BUILTIN(__builtin_rotateleft64) +# define XXH_rotl32 __builtin_rotateleft32 +# define XXH_rotl64 __builtin_rotateleft64 +/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ +#elif defined(_MSC_VER) +# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl64(x,r) _rotl64(x,r) +#else +# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) +#endif + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap32 _byteswap_ulong +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap32 __builtin_bswap32 +#else +static xxh_u32 XXH_swap32 (xxh_u32 x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} +#endif + + +/* *************************** +* Memory reads +*****************************/ +typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; + +/* + * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. + * + * This is ideal for older compilers which don't inline memcpy. + */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u32)bytePtr[1] << 8) + | ((xxh_u32)bytePtr[2] << 16) + | ((xxh_u32)bytePtr[3] << 24); +} + +XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[3] + | ((xxh_u32)bytePtr[2] << 8) + | ((xxh_u32)bytePtr[1] << 16) + | ((xxh_u32)bytePtr[0] << 24); +} + +#else +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); +} + +static xxh_u32 XXH_readBE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH_readLE32_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) { + return XXH_readLE32(ptr); + } else { + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); + } +} + + +/* ************************************* +* Misc +***************************************/ +XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } + + +/* ******************************************************************* +* 32-bit hash functions +*********************************************************************/ +static const xxh_u32 XXH_PRIME32_1 = 0x9E3779B1U; /* 0b10011110001101110111100110110001 */ +static const xxh_u32 XXH_PRIME32_2 = 0x85EBCA77U; /* 0b10000101111010111100101001110111 */ +static const xxh_u32 XXH_PRIME32_3 = 0xC2B2AE3DU; /* 0b11000010101100101010111000111101 */ +static const xxh_u32 XXH_PRIME32_4 = 0x27D4EB2FU; /* 0b00100111110101001110101100101111 */ +static const xxh_u32 XXH_PRIME32_5 = 0x165667B1U; /* 0b00010110010101100110011110110001 */ + +#ifdef XXH_OLD_NAMES +# define PRIME32_1 XXH_PRIME32_1 +# define PRIME32_2 XXH_PRIME32_2 +# define PRIME32_3 XXH_PRIME32_3 +# define PRIME32_4 XXH_PRIME32_4 +# define PRIME32_5 XXH_PRIME32_5 +#endif + +static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) +{ + acc += input * XXH_PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= XXH_PRIME32_1; +#if defined(__GNUC__) && defined(__SSE4_1__) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* + * UGLY HACK: + * This inline assembly hack forces acc into a normal register. This is the + * only thing that prevents GCC and Clang from autovectorizing the XXH32 + * loop (pragmas and attributes don't work for some resason) without globally + * disabling SSE4.1. + * + * The reason we want to avoid vectorization is because despite working on + * 4 integers at a time, there are multiple factors slowing XXH32 down on + * SSE4: + * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on + * newer chips!) making it slightly slower to multiply four integers at + * once compared to four integers independently. Even when pmulld was + * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE + * just to multiply unless doing a long operation. + * + * - Four instructions are required to rotate, + * movqda tmp, v // not required with VEX encoding + * pslld tmp, 13 // tmp <<= 13 + * psrld v, 19 // x >>= 19 + * por v, tmp // x |= tmp + * compared to one for scalar: + * roll v, 13 // reliably fast across the board + * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason + * + * - Instruction level parallelism is actually more beneficial here because + * the SIMD actually serializes this operation: While v1 is rotating, v2 + * can load data, while v3 can multiply. SSE forces them to operate + * together. + * + * How this hack works: + * __asm__("" // Declare an assembly block but don't declare any instructions + * : // However, as an Input/Output Operand, + * "+r" // constrain a read/write operand (+) as a general purpose register (r). + * (acc) // and set acc as the operand + * ); + * + * Because of the 'r', the compiler has promised that seed will be in a + * general purpose register and the '+' says that it will be 'read/write', + * so it has to assume it has changed. It is like volatile without all the + * loads and stores. + * + * Since the argument has to be in a normal register (not an SSE register), + * each time XXH32_round is called, it is impossible to vectorize. + */ + __asm__("" : "+r" (acc)); +#endif + return acc; +} + +/* mix all bits */ +static xxh_u32 XXH32_avalanche(xxh_u32 h32) +{ + h32 ^= h32 >> 15; + h32 *= XXH_PRIME32_2; + h32 ^= h32 >> 13; + h32 *= XXH_PRIME32_3; + h32 ^= h32 >> 16; + return(h32); +} + +#define XXH_get32bits(p) XXH_readLE32_align(p, align) + +static xxh_u32 +XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1 do { \ + h32 += (*ptr++) * XXH_PRIME32_5; \ + h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \ +} while (0) + +#define XXH_PROCESS4 do { \ + h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \ + ptr += 4; \ + h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \ +} while (0) + + /* Compact rerolled version */ + if (XXH_REROLL) { + len &= 15; + while (len >= 4) { + XXH_PROCESS4; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1; + --len; + } + return XXH32_avalanche(h32); + } else { + switch(len&15) /* or switch(bEnd - p) */ { + case 12: XXH_PROCESS4; + /* fallthrough */ + case 8: XXH_PROCESS4; + /* fallthrough */ + case 4: XXH_PROCESS4; + return XXH32_avalanche(h32); + + case 13: XXH_PROCESS4; + /* fallthrough */ + case 9: XXH_PROCESS4; + /* fallthrough */ + case 5: XXH_PROCESS4; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 14: XXH_PROCESS4; + /* fallthrough */ + case 10: XXH_PROCESS4; + /* fallthrough */ + case 6: XXH_PROCESS4; + XXH_PROCESS1; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 15: XXH_PROCESS4; + /* fallthrough */ + case 11: XXH_PROCESS4; + /* fallthrough */ + case 7: XXH_PROCESS4; + /* fallthrough */ + case 3: XXH_PROCESS1; + /* fallthrough */ + case 2: XXH_PROCESS1; + /* fallthrough */ + case 1: XXH_PROCESS1; + /* fallthrough */ + case 0: return XXH32_avalanche(h32); + } + XXH_ASSERT(0); + return h32; /* reaching this point is deemed impossible */ + } +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1 XXH_PROCESS1 +# define PROCESS4 XXH_PROCESS4 +#else +# undef XXH_PROCESS1 +# undef XXH_PROCESS4 +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) +{ + const xxh_u8* bEnd = input + len; + xxh_u32 h32; + +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + if (input==NULL) { + len=0; + bEnd=input=(const xxh_u8*)(size_t)16; + } +#endif + + if (len>=16) { + const xxh_u8* const limit = bEnd - 15; + xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + xxh_u32 v2 = seed + XXH_PRIME32_2; + xxh_u32 v3 = seed + 0; + xxh_u32 v4 = seed - XXH_PRIME32_1; + + do { + v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; + v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; + v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; + v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; + } while (input < limit); + + h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); + } else { + h32 = seed + XXH_PRIME32_5; + } + + h32 += (xxh_u32)len; + + return XXH32_finalize(h32, input, len&15, align); +} + + +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH32_state_t state; + XXH32_reset(&state, seed); + XXH32_update(&state, (const xxh_u8*)input, len); + return XXH32_digest(&state); + +#else + + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); +#endif +} + + + +/******* Hash streaming *******/ + +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) +{ + return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); +} +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) +{ + memcpy(dstState, srcState, sizeof(*dstState)); +} + +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) +{ + XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ + memset(&state, 0, sizeof(state)); + state.v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + state.v2 = seed + XXH_PRIME32_2; + state.v3 = seed + 0; + state.v4 = seed - XXH_PRIME32_1; + /* do not write into reserved, planned to be removed in a future version */ + memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved)); + return XXH_OK; +} + + +XXH_PUBLIC_API XXH_errorcode +XXH32_update(XXH32_state_t* state, const void* input, size_t len) +{ + if (input==NULL) +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + return XXH_OK; +#else + return XXH_ERROR; +#endif + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len_32 += (XXH32_hash_t)len; + state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); + + if (state->memsize + len < 16) { /* fill in tmp buffer */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); + state->memsize += (XXH32_hash_t)len; + return XXH_OK; + } + + if (state->memsize) { /* some data left from previous update */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); + { const xxh_u32* p32 = state->mem32; + state->v1 = XXH32_round(state->v1, XXH_readLE32(p32)); p32++; + state->v2 = XXH32_round(state->v2, XXH_readLE32(p32)); p32++; + state->v3 = XXH32_round(state->v3, XXH_readLE32(p32)); p32++; + state->v4 = XXH32_round(state->v4, XXH_readLE32(p32)); + } + p += 16-state->memsize; + state->memsize = 0; + } + + if (p <= bEnd-16) { + const xxh_u8* const limit = bEnd - 16; + xxh_u32 v1 = state->v1; + xxh_u32 v2 = state->v2; + xxh_u32 v3 = state->v3; + xxh_u32 v4 = state->v4; + + do { + v1 = XXH32_round(v1, XXH_readLE32(p)); p+=4; + v2 = XXH32_round(v2, XXH_readLE32(p)); p+=4; + v3 = XXH32_round(v3, XXH_readLE32(p)); p+=4; + v4 = XXH32_round(v4, XXH_readLE32(p)); p+=4; + } while (p<=limit); + + state->v1 = v1; + state->v2 = v2; + state->v3 = v3; + state->v4 = v4; + } + + if (p < bEnd) { + XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* state) +{ + xxh_u32 h32; + + if (state->large_len) { + h32 = XXH_rotl32(state->v1, 1) + + XXH_rotl32(state->v2, 7) + + XXH_rotl32(state->v3, 12) + + XXH_rotl32(state->v4, 18); + } else { + h32 = state->v3 /* == seed */ + XXH_PRIME32_5; + } + + h32 += state->total_len_32; + + return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/* + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * + * The canonical representation uses big endian convention, the same convention + * as human-readable numbers (large digits first). + * + * This way, hash values can be written into a file or buffer, remaining + * comparable across different systems. + * + * The following functions allow transformation of hash values to and from their + * canonical format. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); + memcpy(dst, &hash, sizeof(*dst)); +} + +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) +{ + return XXH_readBE32(src); +} + + +#ifndef XXH_NO_LONG_LONG + +/* ******************************************************************* +* 64-bit hash functions +*********************************************************************/ + +/******* Memory access *******/ + +typedef XXH64_hash_t xxh_u64; + +#ifdef XXH_OLD_NAMES +# define U64 xxh_u64 +#endif + +/*! + * XXH_REROLL_XXH64: + * Whether to reroll the XXH64_finalize() loop. + * + * Just like XXH32, we can unroll the XXH64_finalize() loop. This can be a + * performance gain on 64-bit hosts, as only one jump is required. + * + * However, on 32-bit hosts, because arithmetic needs to be done with two 32-bit + * registers, and 64-bit arithmetic needs to be simulated, it isn't beneficial + * to unroll. The code becomes ridiculously large (the largest function in the + * binary on i386!), and rerolling it saves anywhere from 3kB to 20kB. It is + * also slightly faster because it fits into cache better and is more likely + * to be inlined by the compiler. + * + * If XXH_REROLL is defined, this is ignored and the loop is always rerolled. + */ +#ifndef XXH_REROLL_XXH64 +# if (defined(__ILP32__) || defined(_ILP32)) /* ILP32 is often defined on 32-bit GCC family */ \ + || !(defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) /* x86-64 */ \ + || defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__) /* aarch64 */ \ + || defined(__PPC64__) || defined(__PPC64LE__) || defined(__ppc64__) || defined(__powerpc64__) /* ppc64 */ \ + || defined(__mips64__) || defined(__mips64)) /* mips64 */ \ + || (!defined(SIZE_MAX) || SIZE_MAX < ULLONG_MAX) /* check limits */ +# define XXH_REROLL_XXH64 1 +# else +# define XXH_REROLL_XXH64 0 +# endif +#endif /* !defined(XXH_REROLL_XXH64) */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE64 and XXH_readBE64. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ +static xxh_u64 XXH_read64(const void* memPtr) { return *(const xxh_u64*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer, but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; +#endif +static xxh_u64 XXH_read64(const void* ptr) +{ + typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64; + return ((const xxh_unalign64*)ptr)->u64; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: https://stackoverflow.com/a/32095106/646947 + */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + xxh_u64 val; + memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap64 _byteswap_uint64 +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap64 __builtin_bswap64 +#else +static xxh_u64 XXH_swap64 (xxh_u64 x) +{ + return ((x << 56) & 0xff00000000000000ULL) | + ((x << 40) & 0x00ff000000000000ULL) | + ((x << 24) & 0x0000ff0000000000ULL) | + ((x << 8) & 0x000000ff00000000ULL) | + ((x >> 8) & 0x00000000ff000000ULL) | + ((x >> 24) & 0x0000000000ff0000ULL) | + ((x >> 40) & 0x000000000000ff00ULL) | + ((x >> 56) & 0x00000000000000ffULL); +} +#endif + + +/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u64)bytePtr[1] << 8) + | ((xxh_u64)bytePtr[2] << 16) + | ((xxh_u64)bytePtr[3] << 24) + | ((xxh_u64)bytePtr[4] << 32) + | ((xxh_u64)bytePtr[5] << 40) + | ((xxh_u64)bytePtr[6] << 48) + | ((xxh_u64)bytePtr[7] << 56); +} + +XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[7] + | ((xxh_u64)bytePtr[6] << 8) + | ((xxh_u64)bytePtr[5] << 16) + | ((xxh_u64)bytePtr[4] << 24) + | ((xxh_u64)bytePtr[3] << 32) + | ((xxh_u64)bytePtr[2] << 40) + | ((xxh_u64)bytePtr[1] << 48) + | ((xxh_u64)bytePtr[0] << 56); +} + +#else +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); +} + +static xxh_u64 XXH_readBE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH_readLE64_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) + return XXH_readLE64(ptr); + else + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); +} + + +/******* xxh64 *******/ + +static const xxh_u64 XXH_PRIME64_1 = 0x9E3779B185EBCA87ULL; /* 0b1001111000110111011110011011000110000101111010111100101010000111 */ +static const xxh_u64 XXH_PRIME64_2 = 0xC2B2AE3D27D4EB4FULL; /* 0b1100001010110010101011100011110100100111110101001110101101001111 */ +static const xxh_u64 XXH_PRIME64_3 = 0x165667B19E3779F9ULL; /* 0b0001011001010110011001111011000110011110001101110111100111111001 */ +static const xxh_u64 XXH_PRIME64_4 = 0x85EBCA77C2B2AE63ULL; /* 0b1000010111101011110010100111011111000010101100101010111001100011 */ +static const xxh_u64 XXH_PRIME64_5 = 0x27D4EB2F165667C5ULL; /* 0b0010011111010100111010110010111100010110010101100110011111000101 */ + +#ifdef XXH_OLD_NAMES +# define PRIME64_1 XXH_PRIME64_1 +# define PRIME64_2 XXH_PRIME64_2 +# define PRIME64_3 XXH_PRIME64_3 +# define PRIME64_4 XXH_PRIME64_4 +# define PRIME64_5 XXH_PRIME64_5 +#endif + +static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) +{ + acc += input * XXH_PRIME64_2; + acc = XXH_rotl64(acc, 31); + acc *= XXH_PRIME64_1; + return acc; +} + +static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) +{ + val = XXH64_round(0, val); + acc ^= val; + acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; + return acc; +} + +static xxh_u64 XXH64_avalanche(xxh_u64 h64) +{ + h64 ^= h64 >> 33; + h64 *= XXH_PRIME64_2; + h64 ^= h64 >> 29; + h64 *= XXH_PRIME64_3; + h64 ^= h64 >> 32; + return h64; +} + + +#define XXH_get64bits(p) XXH_readLE64_align(p, align) + +static xxh_u64 +XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1_64 do { \ + h64 ^= (*ptr++) * XXH_PRIME64_5; \ + h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; \ +} while (0) + +#define XXH_PROCESS4_64 do { \ + h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; \ + ptr += 4; \ + h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; \ +} while (0) + +#define XXH_PROCESS8_64 do { \ + xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); \ + ptr += 8; \ + h64 ^= k1; \ + h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; \ +} while (0) + + /* Rerolled version for 32-bit targets is faster and much smaller. */ + if (XXH_REROLL || XXH_REROLL_XXH64) { + len &= 31; + while (len >= 8) { + XXH_PROCESS8_64; + len -= 8; + } + if (len >= 4) { + XXH_PROCESS4_64; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1_64; + --len; + } + return XXH64_avalanche(h64); + } else { + switch(len & 31) { + case 24: XXH_PROCESS8_64; + /* fallthrough */ + case 16: XXH_PROCESS8_64; + /* fallthrough */ + case 8: XXH_PROCESS8_64; + return XXH64_avalanche(h64); + + case 28: XXH_PROCESS8_64; + /* fallthrough */ + case 20: XXH_PROCESS8_64; + /* fallthrough */ + case 12: XXH_PROCESS8_64; + /* fallthrough */ + case 4: XXH_PROCESS4_64; + return XXH64_avalanche(h64); + + case 25: XXH_PROCESS8_64; + /* fallthrough */ + case 17: XXH_PROCESS8_64; + /* fallthrough */ + case 9: XXH_PROCESS8_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 29: XXH_PROCESS8_64; + /* fallthrough */ + case 21: XXH_PROCESS8_64; + /* fallthrough */ + case 13: XXH_PROCESS8_64; + /* fallthrough */ + case 5: XXH_PROCESS4_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 26: XXH_PROCESS8_64; + /* fallthrough */ + case 18: XXH_PROCESS8_64; + /* fallthrough */ + case 10: XXH_PROCESS8_64; + XXH_PROCESS1_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 30: XXH_PROCESS8_64; + /* fallthrough */ + case 22: XXH_PROCESS8_64; + /* fallthrough */ + case 14: XXH_PROCESS8_64; + /* fallthrough */ + case 6: XXH_PROCESS4_64; + XXH_PROCESS1_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 27: XXH_PROCESS8_64; + /* fallthrough */ + case 19: XXH_PROCESS8_64; + /* fallthrough */ + case 11: XXH_PROCESS8_64; + XXH_PROCESS1_64; + XXH_PROCESS1_64; + XXH_PROCESS1_64; + return XXH64_avalanche(h64); + + case 31: XXH_PROCESS8_64; + /* fallthrough */ + case 23: XXH_PROCESS8_64; + /* fallthrough */ + case 15: XXH_PROCESS8_64; + /* fallthrough */ + case 7: XXH_PROCESS4_64; + /* fallthrough */ + case 3: XXH_PROCESS1_64; + /* fallthrough */ + case 2: XXH_PROCESS1_64; + /* fallthrough */ + case 1: XXH_PROCESS1_64; + /* fallthrough */ + case 0: return XXH64_avalanche(h64); + } + } + /* impossible to reach */ + XXH_ASSERT(0); + return 0; /* unreachable, but some compilers complain without it */ +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1_64 XXH_PROCESS1_64 +# define PROCESS4_64 XXH_PROCESS4_64 +# define PROCESS8_64 XXH_PROCESS8_64 +#else +# undef XXH_PROCESS1_64 +# undef XXH_PROCESS4_64 +# undef XXH_PROCESS8_64 +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) +{ + const xxh_u8* bEnd = input + len; + xxh_u64 h64; + +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + if (input==NULL) { + len=0; + bEnd=input=(const xxh_u8*)(size_t)32; + } +#endif + + if (len>=32) { + const xxh_u8* const limit = bEnd - 32; + xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + xxh_u64 v2 = seed + XXH_PRIME64_2; + xxh_u64 v3 = seed + 0; + xxh_u64 v4 = seed - XXH_PRIME64_1; + + do { + v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; + v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; + v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; + v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; + } while (input<=limit); + + h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); + h64 = XXH64_mergeRound(h64, v1); + h64 = XXH64_mergeRound(h64, v2); + h64 = XXH64_mergeRound(h64, v3); + h64 = XXH64_mergeRound(h64, v4); + + } else { + h64 = seed + XXH_PRIME64_5; + } + + h64 += (xxh_u64) len; + + return XXH64_finalize(h64, input, len, align); +} + + +XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t len, XXH64_hash_t seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH64_state_t state; + XXH64_reset(&state, seed); + XXH64_update(&state, (const xxh_u8*)input, len); + return XXH64_digest(&state); + +#else + + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ + return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); + +#endif +} + +/******* Hash Streaming *******/ + +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) +{ + return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); +} +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState) +{ + memcpy(dstState, srcState, sizeof(*dstState)); +} + +XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, XXH64_hash_t seed) +{ + XXH64_state_t state; /* use a local state to memcpy() in order to avoid strict-aliasing warnings */ + memset(&state, 0, sizeof(state)); + state.v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + state.v2 = seed + XXH_PRIME64_2; + state.v3 = seed + 0; + state.v4 = seed - XXH_PRIME64_1; + /* do not write into reserved64, might be removed in a future version */ + memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved64)); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH64_update (XXH64_state_t* state, const void* input, size_t len) +{ + if (input==NULL) +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + return XXH_OK; +#else + return XXH_ERROR; +#endif + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len += len; + + if (state->memsize + len < 32) { /* fill in tmp buffer */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); + state->memsize += (xxh_u32)len; + return XXH_OK; + } + + if (state->memsize) { /* tmp buffer is full */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); + state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0)); + state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1)); + state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2)); + state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3)); + p += 32-state->memsize; + state->memsize = 0; + } + + if (p+32 <= bEnd) { + const xxh_u8* const limit = bEnd - 32; + xxh_u64 v1 = state->v1; + xxh_u64 v2 = state->v2; + xxh_u64 v3 = state->v3; + xxh_u64 v4 = state->v4; + + do { + v1 = XXH64_round(v1, XXH_readLE64(p)); p+=8; + v2 = XXH64_round(v2, XXH_readLE64(p)); p+=8; + v3 = XXH64_round(v3, XXH_readLE64(p)); p+=8; + v4 = XXH64_round(v4, XXH_readLE64(p)); p+=8; + } while (p<=limit); + + state->v1 = v1; + state->v2 = v2; + state->v3 = v3; + state->v4 = v4; + } + + if (p < bEnd) { + XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* state) +{ + xxh_u64 h64; + + if (state->total_len >= 32) { + xxh_u64 const v1 = state->v1; + xxh_u64 const v2 = state->v2; + xxh_u64 const v3 = state->v3; + xxh_u64 const v4 = state->v4; + + h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); + h64 = XXH64_mergeRound(h64, v1); + h64 = XXH64_mergeRound(h64, v2); + h64 = XXH64_mergeRound(h64, v3); + h64 = XXH64_mergeRound(h64, v4); + } else { + h64 = state->v3 /*seed*/ + XXH_PRIME64_5; + } + + h64 += (xxh_u64) state->total_len; + + return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); +} + + +/******* Canonical representation *******/ + +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); + memcpy(dst, &hash, sizeof(*dst)); +} + +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) +{ + return XXH_readBE64(src); +} + + + +/* ********************************************************************* +* XXH3 +* New generation hash designed for speed on small keys and vectorization +************************************************************************ */ + +/* === Compiler specifics === */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ +# define XXH_RESTRICT restrict +#else +/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */ +# define XXH_RESTRICT /* disable */ +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) \ + || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ + || defined(__clang__) +# define XXH_likely(x) __builtin_expect(x, 1) +# define XXH_unlikely(x) __builtin_expect(x, 0) +#else +# define XXH_likely(x) (x) +# define XXH_unlikely(x) (x) +#endif + +#if defined(__GNUC__) +# if defined(__AVX2__) +# include +# elif defined(__SSE2__) +# include +# elif defined(__ARM_NEON__) || defined(__ARM_NEON) +# define inline __inline__ /* circumvent a clang bug */ +# include +# undef inline +# endif +#elif defined(_MSC_VER) +# include +#endif + +/* + * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while + * remaining a true 64-bit/128-bit hash function. + * + * This is done by prioritizing a subset of 64-bit operations that can be + * emulated without too many steps on the average 32-bit machine. + * + * For example, these two lines seem similar, and run equally fast on 64-bit: + * + * xxh_u64 x; + * x ^= (x >> 47); // good + * x ^= (x >> 13); // bad + * + * However, to a 32-bit machine, there is a major difference. + * + * x ^= (x >> 47) looks like this: + * + * x.lo ^= (x.hi >> (47 - 32)); + * + * while x ^= (x >> 13) looks like this: + * + * // note: funnel shifts are not usually cheap. + * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); + * x.hi ^= (x.hi >> 13); + * + * The first one is significantly faster than the second, simply because the + * shift is larger than 32. This means: + * - All the bits we need are in the upper 32 bits, so we can ignore the lower + * 32 bits in the shift. + * - The shift result will always fit in the lower 32 bits, and therefore, + * we can ignore the upper 32 bits in the xor. + * + * Thanks to this optimization, XXH3 only requires these features to be efficient: + * + * - Usable unaligned access + * - A 32-bit or 64-bit ALU + * - If 32-bit, a decent ADC instruction + * - A 32 or 64-bit multiply with a 64-bit result + * - For the 128-bit variant, a decent byteswap helps short inputs. + * + * The first two are already required by XXH32, and almost all 32-bit and 64-bit + * platforms which can run XXH32 can run XXH3 efficiently. + * + * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one + * notable exception. + * + * First of all, Thumb-1 lacks support for the UMULL instruction which + * performs the important long multiply. This means numerous __aeabi_lmul + * calls. + * + * Second of all, the 8 functional registers are just not enough. + * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need + * Lo registers, and this shuffling results in thousands more MOVs than A32. + * + * A32 and T32 don't have this limitation. They can access all 14 registers, + * do a 32->64 multiply with UMULL, and the flexible operand allowing free + * shifts is helpful, too. + * + * Therefore, we do a quick sanity check. + * + * If compiling Thumb-1 for a target which supports ARM instructions, we will + * emit a warning, as it is not a "sane" platform to compile for. + * + * Usually, if this happens, it is because of an accident and you probably need + * to specify -march, as you likely meant to compile for a newer architecture. + * + * Credit: large sections of the vectorial and asm source code paths + * have been contributed by @easyaspi314 + */ +#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) +# warning "XXH3 is highly inefficient without ARM or Thumb-2." +#endif + +/* ========================================== + * Vectorization detection + * ========================================== */ +#define XXH_SCALAR 0 /* Portable scalar version */ +#define XXH_SSE2 1 /* SSE2 for Pentium 4 and all x86_64 */ +#define XXH_AVX2 2 /* AVX2 for Haswell and Bulldozer */ +#define XXH_AVX512 3 /* AVX512 for Skylake and Icelake */ +#define XXH_NEON 4 /* NEON for most ARMv7-A and all AArch64 */ +#define XXH_VSX 5 /* VSX and ZVector for POWER8/z13 */ + +#ifndef XXH_VECTOR /* can be defined on command line */ +# if defined(__AVX512F__) +# define XXH_VECTOR XXH_AVX512 +# elif defined(__AVX2__) +# define XXH_VECTOR XXH_AVX2 +# elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) +# define XXH_VECTOR XXH_SSE2 +# elif defined(__GNUC__) /* msvc support maybe later */ \ + && (defined(__ARM_NEON__) || defined(__ARM_NEON)) \ + && (defined(__LITTLE_ENDIAN__) /* We only support little endian NEON */ \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +# define XXH_VECTOR XXH_NEON +# elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ + || (defined(__s390x__) && defined(__VEC__)) \ + && defined(__GNUC__) /* TODO: IBM XL */ +# define XXH_VECTOR XXH_VSX +# else +# define XXH_VECTOR XXH_SCALAR +# endif +#endif + +/* + * Controls the alignment of the accumulator, + * for compatibility with aligned vector loads, which are usually faster. + */ +#ifndef XXH_ACC_ALIGN +# if defined(XXH_X86DISPATCH) +# define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ +# elif XXH_VECTOR == XXH_SCALAR /* scalar */ +# define XXH_ACC_ALIGN 8 +# elif XXH_VECTOR == XXH_SSE2 /* sse2 */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX2 /* avx2 */ +# define XXH_ACC_ALIGN 32 +# elif XXH_VECTOR == XXH_NEON /* neon */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_VSX /* vsx */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX512 /* avx512 */ +# define XXH_ACC_ALIGN 64 +# endif +#endif + +#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ + || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 +# define XXH_SEC_ALIGN XXH_ACC_ALIGN +#else +# define XXH_SEC_ALIGN 8 +#endif + +/* + * UGLY HACK: + * GCC usually generates the best code with -O3 for xxHash. + * + * However, when targeting AVX2, it is overzealous in its unrolling resulting + * in code roughly 3/4 the speed of Clang. + * + * There are other issues, such as GCC splitting _mm256_loadu_si256 into + * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which + * only applies to Sandy and Ivy Bridge... which don't even support AVX2. + * + * That is why when compiling the AVX2 version, it is recommended to use either + * -O2 -mavx2 -march=haswell + * or + * -O2 -mavx2 -mno-avx256-split-unaligned-load + * for decent performance, or to use Clang instead. + * + * Fortunately, we can control the first one with a pragma that forces GCC into + * -O2, but the other one we can't control without "failed to inline always + * inline function due to target mismatch" warnings. + */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ +# pragma GCC push_options +# pragma GCC optimize("-O2") +#endif + + +#if XXH_VECTOR == XXH_NEON +/* + * NEON's setup for vmlal_u32 is a little more complicated than it is on + * SSE2, AVX2, and VSX. + * + * While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast. + * + * To do the same operation, the 128-bit 'Q' register needs to be split into + * two 64-bit 'D' registers, performing this operation:: + * + * [ a | b ] + * | '---------. .--------' | + * | x | + * | .---------' '--------. | + * [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[ a >> 32 | b >> 32 ] + * + * Due to significant changes in aarch64, the fastest method for aarch64 is + * completely different than the fastest method for ARMv7-A. + * + * ARMv7-A treats D registers as unions overlaying Q registers, so modifying + * D11 will modify the high half of Q5. This is similar to how modifying AH + * will only affect bits 8-15 of AX on x86. + * + * VZIP takes two registers, and puts even lanes in one register and odd lanes + * in the other. + * + * On ARMv7-A, this strangely modifies both parameters in place instead of + * taking the usual 3-operand form. + * + * Therefore, if we want to do this, we can simply use a D-form VZIP.32 on the + * lower and upper halves of the Q register to end up with the high and low + * halves where we want - all in one instruction. + * + * vzip.32 d10, d11 @ d10 = { d10[0], d11[0] }; d11 = { d10[1], d11[1] } + * + * Unfortunately we need inline assembly for this: Instructions modifying two + * registers at once is not possible in GCC or Clang's IR, and they have to + * create a copy. + * + * aarch64 requires a different approach. + * + * In order to make it easier to write a decent compiler for aarch64, many + * quirks were removed, such as conditional execution. + * + * NEON was also affected by this. + * + * aarch64 cannot access the high bits of a Q-form register, and writes to a + * D-form register zero the high bits, similar to how writes to W-form scalar + * registers (or DWORD registers on x86_64) work. + * + * The formerly free vget_high intrinsics now require a vext (with a few + * exceptions) + * + * Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the equivalent + * of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to only modify one + * operand. + * + * The equivalent of the VZIP.32 on the lower and upper halves would be this + * mess: + * + * ext v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0], v0[1] } + * zip1 v1.2s, v0.2s, v2.2s // v1 = { v0[0], v2[0] } + * zip2 v0.2s, v0.2s, v1.2s // v0 = { v0[1], v2[1] } + * + * Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64 (SHRN): + * + * shrn v1.2s, v0.2d, #32 // v1 = (uint32x2_t)(v0 >> 32); + * xtn v0.2s, v0.2d // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF); + * + * This is available on ARMv7-A, but is less efficient than a single VZIP.32. + */ + +/* + * Function-like macro: + * void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi) + * { + * outLo = (uint32x2_t)(in & 0xFFFFFFFF); + * outHi = (uint32x2_t)(in >> 32); + * in = UNDEFINED; + * } + */ +# if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \ + && defined(__GNUC__) \ + && !defined(__aarch64__) && !defined(__arm64__) +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \ + /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \ + /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \ + __asm__("vzip.32 %e0, %f0" : "+w" (in)); \ + (outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \ + (outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \ + } while (0) +# else +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + (outLo) = vmovn_u64 (in); \ + (outHi) = vshrn_n_u64 ((in), 32); \ + } while (0) +# endif +#endif /* XXH_VECTOR == XXH_NEON */ + +/* + * VSX and Z Vector helpers. + * + * This is very messy, and any pull requests to clean this up are welcome. + * + * There are a lot of problems with supporting VSX and s390x, due to + * inconsistent intrinsics, spotty coverage, and multiple endiannesses. + */ +#if XXH_VECTOR == XXH_VSX +# if defined(__s390x__) +# include +# else +/* gcc's altivec.h can have the unwanted consequence to unconditionally + * #define bool, vector, and pixel keywords, + * with bad consequences for programs already using these keywords for other purposes. + * The paragraph defining these macros is skipped when __APPLE_ALTIVEC__ is defined. + * __APPLE_ALTIVEC__ is _generally_ defined automatically by the compiler, + * but it seems that, in some cases, it isn't. + * Force the build macro to be defined, so that keywords are not altered. + */ +# if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__) +# define __APPLE_ALTIVEC__ +# endif +# include +# endif + +typedef __vector unsigned long long xxh_u64x2; +typedef __vector unsigned char xxh_u8x16; +typedef __vector unsigned xxh_u32x4; + +# ifndef XXH_VSX_BE +# if defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_VSX_BE 1 +# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "-maltivec=be is not recommended. Please use native endianness." +# define XXH_VSX_BE 1 +# else +# define XXH_VSX_BE 0 +# endif +# endif /* !defined(XXH_VSX_BE) */ + +# if XXH_VSX_BE +/* A wrapper for POWER9's vec_revb. */ +# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) +# define XXH_vec_revb vec_revb +# else +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) +{ + xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; + return vec_perm(val, val, vByteSwap); +} +# endif +# endif /* XXH_VSX_BE */ + +/* + * Performs an unaligned load and byte swaps it on big endian. + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) +{ + xxh_u64x2 ret; + memcpy(&ret, ptr, sizeof(xxh_u64x2)); +# if XXH_VSX_BE + ret = XXH_vec_revb(ret); +# endif + return ret; +} + +/* + * vec_mulo and vec_mule are very problematic intrinsics on PowerPC + * + * These intrinsics weren't added until GCC 8, despite existing for a while, + * and they are endian dependent. Also, their meaning swap depending on version. + * */ +# if defined(__s390x__) + /* s390x is always big endian, no issue on this platform */ +# define XXH_vec_mulo vec_mulo +# define XXH_vec_mule vec_mule +# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) +/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ +# define XXH_vec_mulo __builtin_altivec_vmulouw +# define XXH_vec_mule __builtin_altivec_vmuleuw +# else +/* gcc needs inline assembly */ +/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +# endif /* XXH_vec_mulo, XXH_vec_mule */ +#endif /* XXH_VECTOR == XXH_VSX */ + + +/* prefetch + * can be disabled, by declaring XXH_NO_PREFETCH build macro */ +#if defined(XXH_NO_PREFETCH) +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# else +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* XXH_NO_PREFETCH */ + + +/* ========================================== + * XXH3 default settings + * ========================================== */ + +#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ + +#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) +# error "default keyset is not large enough" +#endif + +/* Pseudorandom secret taken directly from FARSH */ +XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { + 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, + 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, + 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, + 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, + 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, + 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, + 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, + 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, + 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, + 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, + 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, + 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, +}; + + +#ifdef XXH_OLD_NAMES +# define kSecret XXH3_kSecret +#endif + +/* + * Calculates a 32-bit to 64-bit long multiply. + * + * Wraps __emulu on MSVC x86 because it tends to call __allmul when it doesn't + * need to (but it shouldn't need to anyways, it is about 7 instructions to do + * a 64x64 multiply...). Since we know that this will _always_ emit MULL, we + * use that instead of the normal method. + * + * If you are compiling for platforms like Thumb-1 and don't have a better option, + * you may also want to write your own long multiply routine here. + * + * XXH_FORCE_INLINE xxh_u64 XXH_mult32to64(xxh_u64 x, xxh_u64 y) + * { + * return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); + * } + */ +#if defined(_MSC_VER) && defined(_M_IX86) +# include +# define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) +#else +/* + * Downcast + upcast is usually better than masking on older compilers like + * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. + * + * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands + * and perform a full 64x64 multiply -- entirely redundant on 32-bit. + */ +# define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) +#endif + +/* + * Calculates a 64->128-bit long multiply. + * + * Uses __uint128_t and _umul128 if available, otherwise uses a scalar version. + */ +static XXH128_hash_t +XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) +{ + /* + * GCC/Clang __uint128_t method. + * + * On most 64-bit targets, GCC and Clang define a __uint128_t type. + * This is usually the best way as it usually uses a native long 64-bit + * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. + * + * Usually. + * + * Despite being a 32-bit platform, Clang (and emscripten) define this type + * despite not having the arithmetic for it. This results in a laggy + * compiler builtin call which calculates a full 128-bit multiply. + * In that case it is best to use the portable one. + * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 + */ +#if defined(__GNUC__) && !defined(__wasm__) \ + && defined(__SIZEOF_INT128__) \ + || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + + __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; + XXH128_hash_t r128; + r128.low64 = (xxh_u64)(product); + r128.high64 = (xxh_u64)(product >> 64); + return r128; + + /* + * MSVC for x64's _umul128 method. + * + * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); + * + * This compiles to single operand MUL on x64. + */ +#elif defined(_M_X64) || defined(_M_IA64) + +#ifndef _MSC_VER +# pragma intrinsic(_umul128) +#endif + xxh_u64 product_high; + xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); + XXH128_hash_t r128; + r128.low64 = product_low; + r128.high64 = product_high; + return r128; + +#else + /* + * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. + * + * This is a fast and simple grade school multiply, which is shown below + * with base 10 arithmetic instead of base 0x100000000. + * + * 9 3 // D2 lhs = 93 + * x 7 5 // D2 rhs = 75 + * ---------- + * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 + * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 + * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 + * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 + * --------- + * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 + * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 + * --------- + * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 + * + * The reasons for adding the products like this are: + * 1. It avoids manual carry tracking. Just like how + * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. + * This avoids a lot of complexity. + * + * 2. It hints for, and on Clang, compiles to, the powerful UMAAL + * instruction available in ARM's Digital Signal Processing extension + * in 32-bit ARMv6 and later, which is shown below: + * + * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) + * { + * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; + * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); + * *RdHi = (xxh_u32)(product >> 32); + * } + * + * This instruction was designed for efficient long multiplication, and + * allows this to be calculated in only 4 instructions at speeds + * comparable to some 64-bit ALUs. + * + * 3. It isn't terrible on other platforms. Usually this will be a couple + * of 32-bit ADD/ADCs. + */ + + /* First calculate all of the cross products. */ + xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); + xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); + xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); + xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + + /* Now add the products together. These will never overflow. */ + xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; + xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); + + XXH128_hash_t r128; + r128.low64 = lower; + r128.high64 = upper; + return r128; +#endif +} + +/* + * Does a 64-bit to 128-bit multiply, then XOR folds it. + * + * The reason for the separate function is to prevent passing too many structs + * around by value. This will hopefully inline the multiply, but we don't force it. + */ +static xxh_u64 +XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) +{ + XXH128_hash_t product = XXH_mult64to128(lhs, rhs); + return product.low64 ^ product.high64; +} + +/* Seems to produce slightly better code on GCC for some reason. */ +XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) +{ + XXH_ASSERT(0 <= shift && shift < 64); + return v64 ^ (v64 >> shift); +} + +/* + * This is a fast avalanche stage, + * suitable when input bits are already partially mixed + */ +static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) +{ + h64 = XXH_xorshift64(h64, 37); + h64 *= 0x165667919E3779F9ULL; + h64 = XXH_xorshift64(h64, 32); + return h64; +} + +/* + * This is a stronger avalanche, + * inspired by Pelle Evensen's rrmxmx + * preferable when input has not been previously mixed + */ +static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) +{ + /* this mix is inspired by Pelle Evensen's rrmxmx */ + h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); + h64 *= 0x9FB21C651E98DF25ULL; + h64 ^= (h64 >> 35) + len ; + h64 *= 0x9FB21C651E98DF25ULL; + return XXH_xorshift64(h64, 28); +} + + +/* ========================================== + * Short keys + * ========================================== + * One of the shortcomings of XXH32 and XXH64 was that their performance was + * sub-optimal on short lengths. It used an iterative algorithm which strongly + * favored lengths that were a multiple of 4 or 8. + * + * Instead of iterating over individual inputs, we use a set of single shot + * functions which piece together a range of lengths and operate in constant time. + * + * Additionally, the number of multiplies has been significantly reduced. This + * reduces latency, especially when emulating 64-bit multiplies on 32-bit. + * + * Depending on the platform, this may or may not be faster than XXH32, but it + * is almost guaranteed to be faster than XXH64. + */ + +/* + * At very short lengths, there isn't enough input to fully hide secrets, or use + * the entire secret. + * + * There is also only a limited amount of mixing we can do before significantly + * impacting performance. + * + * Therefore, we use different sections of the secret and always mix two secret + * samples with an XOR. This should have no effect on performance on the + * seedless or withSeed variants because everything _should_ be constant folded + * by modern compilers. + * + * The XOR mixing hides individual parts of the secret and increases entropy. + * + * This adds an extra layer of strength for custom secrets. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combined = { input[0], 0x01, input[0], input[0] } + * len = 2: combined = { input[1], 0x02, input[0], input[1] } + * len = 3: combined = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; + return XXH64_avalanche(keyed); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len < 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input1 = XXH_readLE32(input); + xxh_u32 const input2 = XXH_readLE32(input + len - 4); + xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; + xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); + xxh_u64 const keyed = input64 ^ bitflip; + return XXH3_rrmxmx(keyed, len); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(8 <= len && len <= 16); + { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; + xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; + xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; + xxh_u64 const acc = len + + XXH_swap64(input_lo) + input_hi + + XXH3_mul128_fold64(input_lo, input_hi); + return XXH3_avalanche(acc); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); + if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); + if (len) return XXH3_len_1to3_64b(input, len, secret, seed); + return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); + } +} + +/* + * DISCLAIMER: There are known *seed-dependent* multicollisions here due to + * multiplication by zero, affecting hashes of lengths 17 to 240. + * + * However, they are very unlikely. + * + * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all + * unseeded non-cryptographic hashes, it does not attempt to defend itself + * against specially crafted inputs, only random inputs. + * + * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes + * cancelling out the secret is taken an arbitrary number of times (addressed + * in XXH3_accumulate_512), this collision is very unlikely with random inputs + * and/or proper seeding: + * + * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a + * function that is only called up to 16 times per hash with up to 240 bytes of + * input. + * + * This is not too bad for a non-cryptographic hash function, especially with + * only 64 bit outputs. + * + * The 128-bit variant (which trades some speed for strength) is NOT affected + * by this, although it is always a good idea to use a proper seed if you care + * about strength. + */ +XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) +{ +#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ + /* + * UGLY HACK: + * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in + * slower code. + * + * By forcing seed64 into a register, we disrupt the cost model and + * cause it to scalarize. See `XXH32_round()` + * + * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, + * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on + * GCC 9.2, despite both emitting scalar code. + * + * GCC generates much better scalar code than Clang for the rest of XXH3, + * which is why finding a more optimal codepath is an interest. + */ + __asm__ ("" : "+r" (seed64)); +#endif + { xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 const input_hi = XXH_readLE64(input+8); + return XXH3_mul128_fold64( + input_lo ^ (XXH_readLE64(secret) + seed64), + input_hi ^ (XXH_readLE64(secret+8) - seed64) + ); + } +} + +/* For mid range keys, XXH3 uses a Mum-hash variant. */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { xxh_u64 acc = len * XXH_PRIME64_1; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc += XXH3_mix16B(input+48, secret+96, seed); + acc += XXH3_mix16B(input+len-64, secret+112, seed); + } + acc += XXH3_mix16B(input+32, secret+64, seed); + acc += XXH3_mix16B(input+len-48, secret+80, seed); + } + acc += XXH3_mix16B(input+16, secret+32, seed); + acc += XXH3_mix16B(input+len-32, secret+48, seed); + } + acc += XXH3_mix16B(input+0, secret+0, seed); + acc += XXH3_mix16B(input+len-16, secret+16, seed); + + return XXH3_avalanche(acc); + } +} + +#define XXH3_MIDSIZE_MAX 240 + +XXH_NO_INLINE XXH64_hash_t +XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + #define XXH3_MIDSIZE_STARTOFFSET 3 + #define XXH3_MIDSIZE_LASTOFFSET 17 + + { xxh_u64 acc = len * XXH_PRIME64_1; + int const nbRounds = (int)len / 16; + int i; + for (i=0; i<8; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); + } + acc = XXH3_avalanche(acc); + XXH_ASSERT(nbRounds >= 8); +#if defined(__clang__) /* Clang */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. + * In everywhere else, it uses scalar code. + * + * For 64->128-bit multiplies, even if the NEON was 100% optimal, it + * would still be slower than UMAAL (see XXH_mult64to128). + * + * Unfortunately, Clang doesn't handle the long multiplies properly and + * converts them to the nonexistent "vmulq_u64" intrinsic, which is then + * scalarized into an ugly mess of VMOV.32 instructions. + * + * This mess is difficult to avoid without turning autovectorization + * off completely, but they are usually relatively minor and/or not + * worth it to fix. + * + * This loop is the easiest to fix, as unlike XXH32, this pragma + * _actually works_ because it is a loop vectorization instead of an + * SLP vectorization. + */ + #pragma clang loop vectorize(disable) +#endif + for (i=8 ; i < nbRounds; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); + } + /* last bytes */ + acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); + return XXH3_avalanche(acc); + } +} + + +/* ======= Long Keys ======= */ + +#define XXH_STRIPE_LEN 64 +#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ +#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) + +#ifdef XXH_OLD_NAMES +# define STRIPE_LEN XXH_STRIPE_LEN +# define ACC_NB XXH_ACC_NB +#endif + +XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) +{ + if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); + memcpy(dst, &v64, sizeof(v64)); +} + +/* Several intrinsic functions below are supposed to accept __int64 as argument, + * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . + * However, several environments do not define __int64 type, + * requiring a workaround. + */ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) + typedef int64_t xxh_i64; +#else + /* the following type must have a width of 64-bit */ + typedef long long xxh_i64; +#endif + +/* + * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. + * + * It is a hardened version of UMAC, based off of FARSH's implementation. + * + * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD + * implementations, and it is ridiculously fast. + * + * We harden it by mixing the original input to the accumulators as well as the product. + * + * This means that in the (relatively likely) case of a multiply by zero, the + * original input is preserved. + * + * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve + * cross-pollination, as otherwise the upper and lower halves would be + * essentially independent. + * + * This doesn't matter on 64-bit hashes since they all get merged together in + * the end, so we skip the extra step. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +#if (XXH_VECTOR == XXH_AVX512) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_AVX512 +# define XXH_TARGET_AVX512 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ALIGN(64) __m512i* const xacc = (__m512i *) acc; + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + + { + /* data_vec = input[0]; */ + __m512i const data_vec = _mm512_loadu_si512 (input); + /* key_vec = secret[0]; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + /* data_key = data_vec ^ key_vec; */ + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); + /* xacc[0] += swap(data_vec); */ + __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); + __m512i const sum = _mm512_add_epi64(*xacc, data_swap); + /* xacc[0] += product; */ + *xacc = _mm512_add_epi64(product, sum); + } +} + +/* + * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. + * + * Multiplication isn't perfect, as explained by Google in HighwayHash: + * + * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + * // varying degrees. In descending order of goodness, bytes + * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + * // As expected, the upper and lower bytes are much worse. + * + * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 + * + * Since our algorithm uses a pseudorandom secret to add some variance into the + * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. + * + * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid + * extraction. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + { XXH_ALIGN(64) __m512i* const xacc = (__m512i*) acc; + const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); + + /* xacc[0] ^= (xacc[0] >> 47) */ + __m512i const acc_vec = *xacc; + __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); + __m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted); + /* xacc[0] ^= secret; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + + /* xacc[0] *= XXH_PRIME32_1; */ + __m512i const data_key_hi = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); + __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); + *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); + XXH_ASSERT(((size_t)customSecret & 63) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); + __m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, -(xxh_i64)seed64); + + XXH_ALIGN(64) const __m512i* const src = (const __m512i*) XXH3_kSecret; + XXH_ALIGN(64) __m512i* const dest = ( __m512i*) customSecret; + int i; + for (i=0; i < nbRounds; ++i) { + /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*', + * this will warn "discards ‘const’ qualifier". */ + union { + XXH_ALIGN(64) const __m512i* cp; + XXH_ALIGN(64) void* p; + } remote_const_void; + remote_const_void.cp = src + i; + dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_AVX2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_AVX2 +# define XXH_TARGET_AVX2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { XXH_ALIGN(32) __m256i* const xacc = (__m256i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xinput = (const __m256i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* data_vec = xinput[i]; */ + __m256i const data_vec = _mm256_loadu_si256 (xinput+i); + /* key_vec = xsecret[i]; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm256_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { XXH_ALIGN(32) __m256i* const xacc = (__m256i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); + __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); + __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); + (void)(&XXH_writeLE64); + XXH_PREFETCH(customSecret); + { __m256i const seed = _mm256_set_epi64x(-(xxh_i64)seed64, (xxh_i64)seed64, -(xxh_i64)seed64, (xxh_i64)seed64); + + XXH_ALIGN(64) const __m256i* const src = (const __m256i*) XXH3_kSecret; + XXH_ALIGN(64) __m256i* dest = ( __m256i*) customSecret; + +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + * The asm hack causes Clang to assume that XXH3_kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + __asm__("" : "+r" (dest)); +# endif + + /* GCC -O2 need unroll loop manually */ + dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed); + dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed); + dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed); + dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed); + dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed); + dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed); + } +} + +#endif + +#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_SSE2 +# define XXH_TARGET_SSE2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* SSE2 is just a half-scale version of the AVX2 version. */ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { XXH_ALIGN(16) __m128i* const xacc = (__m128i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xinput = (const __m128i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* data_vec = xinput[i]; */ + __m128i const data_vec = _mm_loadu_si128 (xinput+i); + /* key_vec = xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m128i const sum = _mm_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { XXH_ALIGN(16) __m128i* const xacc = (__m128i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); + __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); + __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); + +# if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 + // MSVC 32bit mode does not support _mm_set_epi64x before 2015 + XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, -(xxh_i64)seed64 }; + __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); +# else + __m128i const seed = _mm_set_epi64x(-(xxh_i64)seed64, (xxh_i64)seed64); +# endif + int i; + + XXH_ALIGN(64) const float* const src = (float const*) XXH3_kSecret; + XXH_ALIGN(XXH_SEC_ALIGN) __m128i* dest = (__m128i*) customSecret; +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + __asm__("" : "+r" (dest)); +# endif + + for (i=0; i < nbRounds; ++i) { + dest[i] = _mm_add_epi64(_mm_castps_si128(_mm_load_ps(src+i*4)), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_NEON) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { + XXH_ALIGN(16) uint64x2_t* const xacc = (uint64x2_t *) acc; + /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ + uint8_t const* const xinput = (const uint8_t *) input; + uint8_t const* const xsecret = (const uint8_t *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN / sizeof(uint64x2_t); i++) { + /* data_vec = xinput[i]; */ + uint8x16_t data_vec = vld1q_u8(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); + uint64x2_t data_key; + uint32x2_t data_key_lo, data_key_hi; + /* xacc[i] += swap(data_vec); */ + uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); + uint64x2_t const swapped = vextq_u64(data64, data64, 1); + xacc[i] = vaddq_u64 (xacc[i], swapped); + /* data_key = data_vec ^ key_vec; */ + data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); + /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (data_key >> 32); + * data_key = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ + xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); + + } + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { uint64x2_t* xacc = (uint64x2_t*) acc; + uint8_t const* xsecret = (uint8_t const*) secret; + uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(uint64x2_t); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + uint64x2_t acc_vec = xacc[i]; + uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47); + uint64x2_t data_vec = veorq_u64 (acc_vec, shifted); + + /* xacc[i] ^= xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); + uint64x2_t data_key = veorq_u64(data_vec, vreinterpretq_u64_u8(key_vec)); + + /* xacc[i] *= XXH_PRIME32_1 */ + uint32x2_t data_key_lo, data_key_hi; + /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (xacc[i] >> 32); + * xacc[i] = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + { /* + * prod_hi = (data_key >> 32) * XXH_PRIME32_1; + * + * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will + * incorrectly "optimize" this: + * tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b)); + * shifted = vshll_n_u32(tmp, 32); + * to this: + * tmp = "vmulq_u64"(a, b); // no such thing! + * shifted = vshlq_n_u64(tmp, 32); + * + * However, unlike SSE, Clang lacks a 64-bit multiply routine + * for NEON, and it scalarizes two 64-bit multiplies instead. + * + * vmull_u32 has the same timing as vmul_u32, and it avoids + * this bug completely. + * See https://bugs.llvm.org/show_bug.cgi?id=39967 + */ + uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime); + /* xacc[i] = prod_hi << 32; */ + xacc[i] = vshlq_n_u64(prod_hi, 32); + /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */ + xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime); + } + } } +} + +#endif + +#if (XXH_VECTOR == XXH_VSX) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + xxh_u64x2* const xacc = (xxh_u64x2*) acc; /* presumed aligned */ + xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */ + xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */ + xxh_u64x2 const v32 = { 32, 32 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* data_vec = xinput[i]; */ + xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i); + /* key_vec = xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + /* shuffled = (data_key << 32) | (data_key >> 32); */ + xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); + /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ + xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); + xacc[i] += product; + + /* swap high and low halves */ +#ifdef __s390x__ + xacc[i] += vec_permi(data_vec, data_vec, 2); +#else + xacc[i] += vec_xxpermdi(data_vec, data_vec, 2); +#endif + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { xxh_u64x2* const xacc = (xxh_u64x2*) acc; + const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret; + /* constants */ + xxh_u64x2 const v32 = { 32, 32 }; + xxh_u64x2 const v47 = { 47, 47 }; + xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + xxh_u64x2 const acc_vec = xacc[i]; + xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); + + /* xacc[i] ^= xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + + /* xacc[i] *= XXH_PRIME32_1 */ + /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ + xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); + /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ + xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); + xacc[i] = prod_odd + (prod_even << v32); + } } +} + +#endif + +/* scalar variants - universal */ + +XXH_FORCE_INLINE void +XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xinput = (const xxh_u8*) input; /* no alignment restriction */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + size_t i; + XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); + for (i=0; i < XXH_ACC_NB; i++) { + xxh_u64 const data_val = XXH_readLE64(xinput + 8*i); + xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + i*8); + xacc[i ^ 1] += data_val; /* swap adjacent lanes */ + xacc[i] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + size_t i; + XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); + for (i=0; i < XXH_ACC_NB; i++) { + xxh_u64 const key64 = XXH_readLE64(xsecret + 8*i); + xxh_u64 acc64 = xacc[i]; + acc64 = XXH_xorshift64(acc64, 47); + acc64 ^= key64; + acc64 *= XXH_PRIME32_1; + xacc[i] = acc64; + } +} + +XXH_FORCE_INLINE void +XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + /* + * We need a separate pointer for the hack below, + * which requires a non-const pointer. + * Any decent compiler will optimize this out otherwise. + */ + const xxh_u8* kSecretPtr = XXH3_kSecret; + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + +#if defined(__clang__) && defined(__aarch64__) + /* + * UGLY HACK: + * Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are + * placed sequentially, in order, at the top of the unrolled loop. + * + * While MOVK is great for generating constants (2 cycles for a 64-bit + * constant compared to 4 cycles for LDR), long MOVK chains stall the + * integer pipelines: + * I L S + * MOVK + * MOVK + * MOVK + * MOVK + * ADD + * SUB STR + * STR + * By forcing loads from memory (as the asm line causes Clang to assume + * that XXH3_kSecretPtr has been changed), the pipelines are used more + * efficiently: + * I L S + * LDR + * ADD LDR + * SUB STR + * STR + * XXH3_64bits_withSeed, len == 256, Snapdragon 835 + * without hack: 2654.4 MB/s + * with hack: 3202.9 MB/s + */ + __asm__("" : "+r" (kSecretPtr)); +#endif + /* + * Note: in debug mode, this overrides the asm optimization + * and Clang will emit MOVK chains again. + */ + XXH_ASSERT(kSecretPtr == XXH3_kSecret); + + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; + int i; + for (i=0; i < nbRounds; i++) { + /* + * The asm hack causes Clang to assume that kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; + xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; + XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); + XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); + } } +} + + +typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*); +typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); +typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); + + +#if (XXH_VECTOR == XXH_AVX512) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx512 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 + +#elif (XXH_VECTOR == XXH_AVX2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 + +#elif (XXH_VECTOR == XXH_SSE2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_sse2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 + +#elif (XXH_VECTOR == XXH_NEON) + +#define XXH3_accumulate_512 XXH3_accumulate_512_neon +#define XXH3_scrambleAcc XXH3_scrambleAcc_neon +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_VSX) + +#define XXH3_accumulate_512 XXH3_accumulate_512_vsx +#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#else /* scalar */ + +#define XXH3_accumulate_512 XXH3_accumulate_512_scalar +#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#endif + + + +#ifndef XXH_PREFETCH_DIST +# ifdef __clang__ +# define XXH_PREFETCH_DIST 320 +# else +# if (XXH_VECTOR == XXH_AVX512) +# define XXH_PREFETCH_DIST 512 +# else +# define XXH_PREFETCH_DIST 384 +# endif +# endif /* __clang__ */ +#endif /* XXH_PREFETCH_DIST */ + +/* + * XXH3_accumulate() + * Loops over XXH3_accumulate_512(). + * Assumption: nbStripes will not overflow the secret size + */ +XXH_FORCE_INLINE void +XXH3_accumulate( xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, + size_t nbStripes, + XXH3_f_accumulate_512 f_acc512) +{ + size_t n; + for (n = 0; n < nbStripes; n++ ) { + const xxh_u8* const in = input + n*XXH_STRIPE_LEN; + XXH_PREFETCH(in + XXH_PREFETCH_DIST); + f_acc512(acc, + in, + secret + n*XXH_SECRET_CONSUME_RATE); + } +} + +XXH_FORCE_INLINE void +XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; + size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; + size_t const nb_blocks = (len - 1) / block_len; + + size_t n; + + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + + for (n = 0; n < nb_blocks; n++) { + XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); + } + + /* last partial block */ + XXH_ASSERT(len > XXH_STRIPE_LEN); + { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; + XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); + XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512); + + /* last stripe */ + { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; +#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ + f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); + } } +} + +XXH_FORCE_INLINE xxh_u64 +XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) +{ + return XXH3_mul128_fold64( + acc[0] ^ XXH_readLE64(secret), + acc[1] ^ XXH_readLE64(secret+8) ); +} + +static XXH64_hash_t +XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) +{ + xxh_u64 result64 = start; + size_t i = 0; + + for (i = 0; i < 4; i++) { + result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); +#if defined(__clang__) /* Clang */ \ + && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Prevent autovectorization on Clang ARMv7-a. Exact same problem as + * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. + * XXH3_64bits, len == 256, Snapdragon 835: + * without hack: 2063.7 MB/s + * with hack: 2560.7 MB/s + */ + __asm__("" : "+r" (result64)); +#endif + } + + return XXH3_avalanche(result64); +} + +#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ + XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, + const void* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + /* do not align on 8, so that the secret is different from the accumulator */ +#define XXH_SECRET_MERGEACCS_START 11 + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + * Since the function is not inlined, the compiler may not be able to understand that, + * in some scenarios, its `secret` argument is actually a compile time constant. + * This variant enforces that the compiler can detect that, + * and uses this opportunity to streamline the generated code for better performance. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * XXH3_hashLong_64b_withSeed(): + * Generate a custom key based on alteration of default XXH3_kSecret with the seed, + * and then use this key for long mode hashing. + * + * This operation is decently fast but nonetheless costs a little bit of time. + * Try to avoid it whenever possible (typically when seed==0). + * + * It's important for performance that XXH3_hashLong is not inlined. Not sure + * why (uop cache maybe?), but the difference is large and easily measurable. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, + XXH64_hash_t seed, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed == 0) + return XXH3_hashLong_64b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed); + return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed(const void* input, size_t len, + XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_64b_withSeed_internal(input, len, seed, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + + +typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong64_f f_hashLong) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secretLen` condition is not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + * Also, note that function signature doesn't offer room to return an error. + */ + if (len <= 16) + return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); +} + + +/* === Public entry point === */ + +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len) +{ + return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); +} + + +/* === XXH3 streaming === */ + +/* + * Malloc's a pointer that is always aligned to align. + * + * This must be freed with `XXH_alignedFree()`. + * + * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte + * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 + * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. + * + * This underalignment previously caused a rather obvious crash which went + * completely unnoticed due to XXH3_createState() not actually being tested. + * Credit to RedSpah for noticing this bug. + * + * The alignment is done manually: Functions like posix_memalign or _mm_malloc + * are avoided: To maintain portability, we would have to write a fallback + * like this anyways, and besides, testing for the existence of library + * functions without relying on external build tools is impossible. + * + * The method is simple: Overallocate, manually align, and store the offset + * to the original behind the returned pointer. + * + * Align must be a power of 2 and 8 <= align <= 128. + */ +static void* XXH_alignedMalloc(size_t s, size_t align) +{ + XXH_ASSERT(align <= 128 && align >= 8); /* range check */ + XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ + XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ + { /* Overallocate to make room for manual realignment and an offset byte */ + xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); + if (base != NULL) { + /* + * Get the offset needed to align this pointer. + * + * Even if the returned pointer is aligned, there will always be + * at least one byte to store the offset to the original pointer. + */ + size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ + /* Add the offset for the now-aligned pointer */ + xxh_u8* ptr = base + offset; + + XXH_ASSERT((size_t)ptr % align == 0); + + /* Store the offset immediately before the returned pointer. */ + ptr[-1] = (xxh_u8)offset; + return ptr; + } + return NULL; + } +} +/* + * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass + * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. + */ +static void XXH_alignedFree(void* p) +{ + if (p != NULL) { + xxh_u8* ptr = (xxh_u8*)p; + /* Get the offset byte we added in XXH_malloc. */ + xxh_u8 offset = ptr[-1]; + /* Free the original malloc'd pointer */ + xxh_u8* base = ptr - offset; + XXH_free(base); + } +} +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) +{ + XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); + if (state==NULL) return NULL; + XXH3_INITSTATE(state); + return state; +} + +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) +{ + XXH_alignedFree(statePtr); + return XXH_OK; +} + +XXH_PUBLIC_API void +XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) +{ + memcpy(dst_state, src_state, sizeof(*dst_state)); +} + +static void +XXH3_64bits_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + size_t const initStart = offsetof(XXH3_state_t, bufferedSize); + size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; + XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); + XXH_ASSERT(statePtr != NULL); + /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ + memset((char*)statePtr + initStart, 0, initLength); + statePtr->acc[0] = XXH_PRIME32_3; + statePtr->acc[1] = XXH_PRIME64_1; + statePtr->acc[2] = XXH_PRIME64_2; + statePtr->acc[3] = XXH_PRIME64_3; + statePtr->acc[4] = XXH_PRIME64_4; + statePtr->acc[5] = XXH_PRIME32_2; + statePtr->acc[6] = XXH_PRIME64_5; + statePtr->acc[7] = XXH_PRIME32_1; + statePtr->seed = seed; + statePtr->extSecret = (const unsigned char*)secret; + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; + statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_64bits_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_64bits_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_64bits_reset(statePtr); + if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_64bits_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/* Note : when XXH3_consumeStripes() is invoked, + * there must be a guarantee that at least one more byte must be consumed from input + * so that the function can blindly consume all stripes using the "normal" secret segment */ +XXH_FORCE_INLINE void +XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, + size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, + const xxh_u8* XXH_RESTRICT input, size_t nbStripes, + const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ + XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); + if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { + /* need a scrambling operation */ + size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; + size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock; + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); + f_scramble(acc, secret + secretLimit); + XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); + *nbStripesSoFarPtr = nbStripesAfterBlock; + } else { + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); + *nbStripesSoFarPtr += nbStripes; + } +} + +/* + * Both XXH3_64bits_update and XXH3_128bits_update use this routine. + */ +XXH_FORCE_INLINE XXH_errorcode +XXH3_update(XXH3_state_t* state, + const xxh_u8* input, size_t len, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + if (input==NULL) +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + return XXH_OK; +#else + return XXH_ERROR; +#endif + + { const xxh_u8* const bEnd = input + len; + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + + state->totalLen += len; + + if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { /* fill in tmp buffer */ + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + /* total input is now > XXH3_INTERNALBUFFER_SIZE */ + + #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) + XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ + + /* + * Internal buffer is partially filled (always, except at beginning) + * Complete it, then consume it. + */ + if (state->bufferedSize) { + size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; + XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); + input += loadSize; + XXH3_consumeStripes(state->acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + state->bufferedSize = 0; + } + XXH_ASSERT(input < bEnd); + + /* Consume input by a multiple of internal buffer size */ + if (input+XXH3_INTERNALBUFFER_SIZE < bEnd) { + const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; + do { + XXH3_consumeStripes(state->acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + input, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + input += XXH3_INTERNALBUFFER_SIZE; + } while (inputbuffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + } + XXH_ASSERT(input < bEnd); + + /* Some remaining input (always) : buffer it */ + XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); + state->bufferedSize = (XXH32_hash_t)(bEnd-input); + } + + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + + +XXH_FORCE_INLINE void +XXH3_digest_long (XXH64_hash_t* acc, + const XXH3_state_t* state, + const unsigned char* secret) +{ + /* + * Digest on a local copy. This way, the state remains unaltered, and it can + * continue ingesting more input afterwards. + */ + memcpy(acc, state->acc, sizeof(state->acc)); + if (state->bufferedSize >= XXH_STRIPE_LEN) { + size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; + size_t nbStripesSoFar = state->nbStripesSoFar; + XXH3_consumeStripes(acc, + &nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, nbStripes, + secret, state->secretLimit, + XXH3_accumulate_512, XXH3_scrambleAcc); + /* last stripe */ + XXH3_accumulate_512(acc, + state->buffer + state->bufferedSize - XXH_STRIPE_LEN, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } else { /* bufferedSize < XXH_STRIPE_LEN */ + xxh_u8 lastStripe[XXH_STRIPE_LEN]; + size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; + XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ + memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); + memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); + XXH3_accumulate_512(acc, + lastStripe, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } +} + +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + return XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + } + /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ + if (state->seed) + return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + + +#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +XXH_PUBLIC_API void +XXH3_generateSecret(void* secretBuffer, const void* customSeed, size_t customSeedSize) +{ + XXH_ASSERT(secretBuffer != NULL); + if (customSeedSize == 0) { + memcpy(secretBuffer, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return; + } + XXH_ASSERT(customSeed != NULL); + + { size_t const segmentSize = sizeof(XXH128_hash_t); + size_t const nbSegments = XXH_SECRET_DEFAULT_SIZE / segmentSize; + XXH128_canonical_t scrambler; + XXH64_hash_t seeds[12]; + size_t segnb; + XXH_ASSERT(nbSegments == 12); + XXH_ASSERT(segmentSize * nbSegments == XXH_SECRET_DEFAULT_SIZE); /* exact multiple */ + XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); + + /* + * Copy customSeed to seeds[], truncating or repeating as necessary. + */ + { size_t toFill = XXH_MIN(customSeedSize, sizeof(seeds)); + size_t filled = toFill; + memcpy(seeds, customSeed, toFill); + while (filled < sizeof(seeds)) { + toFill = XXH_MIN(filled, sizeof(seeds) - filled); + memcpy((char*)seeds + filled, seeds, toFill); + filled += toFill; + } } + + /* generate secret */ + memcpy(secretBuffer, &scrambler, sizeof(scrambler)); + for (segnb=1; segnb < nbSegments; segnb++) { + size_t const segmentStart = segnb * segmentSize; + XXH128_canonical_t segment; + XXH128_canonicalFromHash(&segment, + XXH128(&scrambler, sizeof(scrambler), XXH_readLE64(seeds + segnb) + segnb) ); + memcpy((char*)secretBuffer + segmentStart, &segment, sizeof(segment)); + } } +} + + +/* ========================================== + * XXH3 128 bits (a.k.a XXH128) + * ========================================== + * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, + * even without counting the significantly larger output size. + * + * For example, extra steps are taken to avoid the seed-dependent collisions + * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). + * + * This strength naturally comes at the cost of some speed, especially on short + * lengths. Note that longer hashes are about as fast as the 64-bit version + * due to it using only a slight modification of the 64-bit loop. + * + * XXH128 is also more oriented towards 64-bit machines. It is still extremely + * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). + */ + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + /* A doubled version of 1to3_64b with different constants. */ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } + * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } + * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); + xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; + xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; + xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; + XXH128_hash_t h128; + h128.low64 = XXH64_avalanche(keyed_lo); + h128.high64 = XXH64_avalanche(keyed_hi); + return h128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); + xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; + xxh_u64 const keyed = input_64 ^ bitflip; + + /* Shift len to the left to ensure it is even, this avoids even multiplies. */ + XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); + + m128.high64 += (m128.low64 << 1); + m128.low64 ^= (m128.high64 >> 3); + + m128.low64 = XXH_xorshift64(m128.low64, 35); + m128.low64 *= 0x9FB21C651E98DF25ULL; + m128.low64 = XXH_xorshift64(m128.low64, 28); + m128.high64 = XXH3_avalanche(m128.high64); + return m128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; + xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; + xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 input_hi = XXH_readLE64(input + len - 8); + XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); + /* + * Put len in the middle of m128 to ensure that the length gets mixed to + * both the low and high bits in the 128x64 multiply below. + */ + m128.low64 += (xxh_u64)(len - 1) << 54; + input_hi ^= bitfliph; + /* + * Add the high 32 bits of input_hi to the high 32 bits of m128, then + * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to + * the high 64 bits of m128. + * + * The best approach to this operation is different on 32-bit and 64-bit. + */ + if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ + /* + * 32-bit optimized version, which is more readable. + * + * On 32-bit, it removes an ADC and delays a dependency between the two + * halves of m128.high64, but it generates an extra mask on 64-bit. + */ + m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); + } else { + /* + * 64-bit optimized (albeit more confusing) version. + * + * Uses some properties of addition and multiplication to remove the mask: + * + * Let: + * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) + * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) + * c = XXH_PRIME32_2 + * + * a + (b * c) + * Inverse Property: x + y - x == y + * a + (b * (1 + c - 1)) + * Distributive Property: x * (y + z) == (x * y) + (x * z) + * a + (b * 1) + (b * (c - 1)) + * Identity Property: x * 1 == x + * a + b + (b * (c - 1)) + * + * Substitute a, b, and c: + * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + * + * Since input_hi.hi + input_hi.lo == input_hi, we get this: + * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + */ + m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); + } + /* m128 ^= XXH_swap64(m128 >> 64); */ + m128.low64 ^= XXH_swap64(m128.high64); + + { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ + XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); + h128.high64 += m128.high64 * XXH_PRIME64_2; + + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = XXH3_avalanche(h128.high64); + return h128; + } } +} + +/* + * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); + if (len) return XXH3_len_1to3_128b(input, len, secret, seed); + { XXH128_hash_t h128; + xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); + xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); + h128.low64 = XXH64_avalanche(seed ^ bitflipl); + h128.high64 = XXH64_avalanche( seed ^ bitfliph); + return h128; + } } +} + +/* + * A bit slower than XXH3_mix16B, but handles multiply by zero better. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, + const xxh_u8* secret, XXH64_hash_t seed) +{ + acc.low64 += XXH3_mix16B (input_1, secret+0, seed); + acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); + acc.high64 += XXH3_mix16B (input_2, secret+16, seed); + acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); + return acc; +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { XXH128_hash_t acc; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); + } + acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); + } + acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); + } + acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_NO_INLINE XXH128_hash_t +XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + { XXH128_hash_t acc; + int const nbRounds = (int)len / 32; + int i; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + for (i=0; i<4; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + (32 * i), + seed); + } + acc.low64 = XXH3_avalanche(acc.low64); + acc.high64 = XXH3_avalanche(acc.high64); + XXH_ASSERT(nbRounds >= 4); + for (i=4 ; i < nbRounds; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)), + seed); + } + /* last bytes */ + acc = XXH128_mix32B(acc, + input + len - 16, + input + len - 32, + secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, + 0ULL - seed); + + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)len * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + secretSize + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)len * XXH_PRIME64_2)); + return h128; + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed64 == 0) + return XXH3_hashLong_128b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed64); + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + +typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const void* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_128bits_internal(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong128_f f_hl128) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secret` conditions are not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + */ + if (len <= 16) + return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hl128(input, len, seed64, secret, secretLen); +} + + +/* === Public XXH128 API === */ + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len) +{ + return XXH3_128bits_internal(input, len, 0, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_default); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_128bits_internal(input, len, 0, + (const xxh_u8*)secret, secretSize, + XXH3_hashLong_128b_withSecret); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_internal(input, len, seed, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_withSeed); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH128(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_withSeed(input, len, seed); +} + + +/* === XXH3 128-bit streaming === */ + +/* + * All the functions are actually the same as for 64-bit streaming variant. + * The only difference is the finalizatiom routine. + */ + +static void +XXH3_128bits_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + XXH3_64bits_reset_internal(statePtr, seed, secret, secretSize); +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_128bits_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_128bits_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_128bits_reset(statePtr); + if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_128bits_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + state->secretLimit + XXH_STRIPE_LEN + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); + return h128; + } + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->seed) + return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + +/* 128-bit utility functions */ + +#include /* memcmp, memcpy */ + +/* return : 1 is equal, 0 if different */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) +{ + /* note : XXH128_hash_t is compact, it has no padding byte */ + return !(memcmp(&h1, &h2, sizeof(h1))); +} + +/* This prototype is compatible with stdlib's qsort(). + * return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) +{ + XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; + XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; + int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); + /* note : bets that, in most cases, hash values are different */ + if (hcmp) return hcmp; + return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); +} + + +/*====== Canonical representation ======*/ +XXH_PUBLIC_API void +XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) { + hash.high64 = XXH_swap64(hash.high64); + hash.low64 = XXH_swap64(hash.low64); + } + memcpy(dst, &hash.high64, sizeof(hash.high64)); + memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH128_hashFromCanonical(const XXH128_canonical_t* src) +{ + XXH128_hash_t h; + h.high64 = XXH_readBE64(src); + h.low64 = XXH_readBE64(src->digest + 8); + return h; +} + +/* Pop our optimization override from above */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ +# pragma GCC pop_options +#endif + +#endif /* XXH_NO_LONG_LONG */ + + +#endif /* XXH_IMPLEMENTATION */ + + +#if defined (__cplusplus) +} +#endif diff -Nru r-cran-rlang-0.4.8/src/internal.c r-cran-rlang-0.4.10/src/internal.c --- r-cran-rlang-0.4.8/src/internal.c 2020-08-12 09:37:14.000000000 +0000 +++ r-cran-rlang-0.4.10/src/internal.c 2020-12-18 09:31:10.000000000 +0000 @@ -9,7 +9,9 @@ #include "internal/expr-interp.c" #include "internal/expr-interp-rotate.c" #include "internal/fn.c" +#include "internal/hash.c" #include "internal/internal.c" +#include "internal/nse-defuse.c" #include "internal/quo.c" #include "internal/utils.c" #include "internal/vec-raw.c" diff -Nru r-cran-rlang-0.4.8/src/lib/cnd.h r-cran-rlang-0.4.10/src/lib/cnd.h --- r-cran-rlang-0.4.8/src/lib/cnd.h 2020-06-26 13:10:13.000000000 +0000 +++ r-cran-rlang-0.4.10/src/lib/cnd.h 2020-11-19 12:47:54.000000000 +0000 @@ -38,7 +38,7 @@ static inline __attribute__((noreturn)) -void r_stop_internal_error(const char* fn, const char* msg) { +void r_stop_internal(const char* fn, const char* msg) { r_abort("Internal error in `%s()`: %s", fn, msg); } diff -Nru r-cran-rlang-0.4.8/src/lib/c-utils.h r-cran-rlang-0.4.10/src/lib/c-utils.h --- r-cran-rlang-0.4.8/src/lib/c-utils.h 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/src/lib/c-utils.h 2020-11-19 12:47:54.000000000 +0000 @@ -0,0 +1,108 @@ +#ifndef RLANG_C_UTILS_H +#define RLANG_C_UTILS_H + +#include +#include "cnd.h" + + +// Adapted from CERT C coding standards +static inline +intmax_t r__intmax_add(intmax_t x, intmax_t y) { + if ((y > 0 && x > (INTMAX_MAX - y)) || + (y < 0 && x < (INTMAX_MIN - y))) { + r_stop_internal("intmax_add", "Values too large to be added."); + } + + return x + y; +} +static inline +intmax_t r__intmax_subtract(intmax_t x, intmax_t y) { + if ((y > 0 && x < (INTMAX_MIN + y)) || + (y < 0 && x < (INTMAX_MAX + y))) { + r_stop_internal("intmax_subtract", "Subtraction resulted in overflow or underflow."); + } + + return x - y; +} + +static inline +r_ssize r_ssize_add(r_ssize x, r_ssize y) { + intmax_t out = r__intmax_add(x, y); + + if (out > R_SSIZE_MAX) { + r_stop_internal("r_ssize_safe_add", "Result too large for an `r_ssize`."); + } + + return (r_ssize) out; +} + +static inline +r_ssize r_ssize_mult(r_ssize x, r_ssize y) { + if (x > 0) { + if (y > 0) { + if (x > (R_SSIZE_MAX / y)) { + goto error; + } + } else { + if (y < (R_SSIZE_MIN / x)) { + goto error; + } + } + } else { + if (y > 0) { + if (x < (R_SSIZE_MIN / y)) { + goto error; + } + } else { + if ( (x != 0) && (y < (R_SSIZE_MAX / x))) { + goto error; + } + } + } + + return x * y; + + error: + r_stop_internal("r_ssize_mult", "Result too large for an `r_ssize`."); +} + +static inline +r_ssize r_ssize_min(r_ssize x, r_ssize y) { + return (y < x) ? y : x; +} + +static inline +r_ssize r_ssize_max(r_ssize x, r_ssize y) { + return (y < x) ? x : y; +} + +static inline +double r_ssize_as_double(r_ssize x) { + if (x > DBL_MAX || x < -DBL_MAX) { + r_stop_internal("r_ssize_as_double", "Result can't be represented as `double`."); + } + + return (double) x; +} + +static inline +r_ssize r_double_as_ssize(double x) { + if (x > R_SSIZE_MAX || x < R_SSIZE_MIN) { + r_stop_internal("r_ssize_as_double", "Result can't be represented as `r_ssize`."); + } + + return (r_ssize) x; +} + +static inline +double r_double_mult(double x, double y) { + double out = x * y; + + if (!isfinite(out)) { + r_stop_internal("r_double_mult", "Can't multiply double values."); + } + + return out; +} + +#endif diff -Nru r-cran-rlang-0.4.8/src/lib/parse.c r-cran-rlang-0.4.10/src/lib/parse.c --- r-cran-rlang-0.4.8/src/lib/parse.c 2018-10-17 08:18:49.000000000 +0000 +++ r-cran-rlang-0.4.10/src/lib/parse.c 2020-11-19 12:47:54.000000000 +0000 @@ -34,6 +34,8 @@ const struct r_op_precedence r_ops_precedence[R_OP_MAX] = { [R_OP_NONE] = { .power = 0, .assoc = 0, .unary = false, .delimited = false }, + [R_OP_BREAK] = { .power = 1, .assoc = 0, .unary = false, .delimited = true }, + [R_OP_NEXT] = { .power = 1, .assoc = 0, .unary = false, .delimited = true }, [R_OP_FUNCTION] = { .power = 5, .assoc = 1, .unary = true, .delimited = false }, [R_OP_QUESTION] = { .power = 10, .assoc = -1, .unary = false, .delimited = false }, [R_OP_QUESTION_UNARY] = { .power = 10, .assoc = -1, .unary = true, .delimited = false }, @@ -95,9 +97,9 @@ bool is_unary = r_node_cddr(call) == r_null; switch (name[0]) { - case 'w': - if (strcmp(name, "while") == 0) { - return R_OP_WHILE; + case 'b': + if (strcmp(name, "break") == 0) { + return R_OP_BREAK; } else { goto none; } @@ -109,15 +111,27 @@ } else { goto none; } + case 'i': + if (strcmp(name, "if") == 0) { + return R_OP_IF; + } else { + goto none; + } + case 'n': + if (strcmp(name, "next") == 0) { + return R_OP_NEXT; + } else { + goto none; + } case 'r': if (strcmp(name, "repeat") == 0) { return R_OP_REPEAT; } else { goto none; } - case 'i': - if (strcmp(name, "if") == 0) { - return R_OP_IF; + case 'w': + if (strcmp(name, "while") == 0) { + return R_OP_WHILE; } else { goto none; } @@ -368,6 +382,8 @@ const char* r_op_as_c_string(enum r_operator op) { switch (op) { case R_OP_NONE: return ""; + case R_OP_BREAK: return "break"; + case R_OP_NEXT: return "next"; case R_OP_WHILE: return "while"; case R_OP_FOR: return "for"; case R_OP_REPEAT: return "repeat"; diff -Nru r-cran-rlang-0.4.8/src/lib/parse.h r-cran-rlang-0.4.10/src/lib/parse.h --- r-cran-rlang-0.4.8/src/lib/parse.h 2018-12-17 14:37:51.000000000 +0000 +++ r-cran-rlang-0.4.10/src/lib/parse.h 2020-11-19 12:47:54.000000000 +0000 @@ -8,6 +8,8 @@ // Examples of silent operators are `else` and `in`. enum r_operator { R_OP_NONE = 0, + R_OP_BREAK, + R_OP_NEXT, R_OP_FUNCTION, R_OP_WHILE, R_OP_FOR, diff -Nru r-cran-rlang-0.4.8/src/lib/rlang.c r-cran-rlang-0.4.10/src/lib/rlang.c --- r-cran-rlang-0.4.8/src/lib/rlang.c 2020-07-07 14:33:41.000000000 +0000 +++ r-cran-rlang-0.4.10/src/lib/rlang.c 2020-11-19 12:47:54.000000000 +0000 @@ -92,7 +92,7 @@ for (int i = R_OP_NONE + 1; i < R_OP_MAX; ++i) { if (r_ops_precedence[i].power == 0) { - r_abort("Internal error: `r_ops_precedence` is not fully initialised"); + Rf_error("Internal error: `r_ops_precedence` is not fully initialised"); } } diff -Nru r-cran-rlang-0.4.8/src/lib/rlang.h r-cran-rlang-0.4.10/src/lib/rlang.h --- r-cran-rlang-0.4.8/src/lib/rlang.h 2020-07-09 09:29:48.000000000 +0000 +++ r-cran-rlang-0.4.10/src/lib/rlang.h 2020-11-19 12:47:54.000000000 +0000 @@ -14,6 +14,7 @@ typedef R_xlen_t r_ssize; #define R_SSIZE_MAX R_XLEN_T_MAX +#define R_SSIZE_MIN (-R_XLEN_T_MAX) r_ssize r_as_ssize(sexp* n); @@ -49,6 +50,13 @@ r_type_function = 99 }; +#include +#if (R_VERSION < R_Version(3, 5, 0)) +# define r_list_deref_const(x) ((sexp* const *) STRING_PTR(x)) +#else +# define r_list_deref_const(x) ((sexp* const *) DATAPTR_RO(x)) +#endif + #define r_null R_NilValue extern sexp* r_shared_true; @@ -70,6 +78,7 @@ #include "attrs.h" #include "debug.h" +#include "c-utils.h" #include "cnd.h" #include "env.h" #include "env-binding.h" diff -Nru r-cran-rlang-0.4.8/src/Makevars r-cran-rlang-0.4.10/src/Makevars --- r-cran-rlang-0.4.8/src/Makevars 2020-07-07 14:33:41.000000000 +0000 +++ r-cran-rlang-0.4.10/src/Makevars 2020-12-18 09:31:10.000000000 +0000 @@ -41,7 +41,9 @@ internal/expr-interp.c \ internal/expr-interp-rotate.c \ internal/fn.c \ + internal/hash.c \ internal/internal.c \ + internal/nse-defuse.c \ internal/quo.c \ internal/utils.c \ internal/vec-raw.c diff -Nru r-cran-rlang-0.4.8/src/version.c r-cran-rlang-0.4.10/src/version.c --- r-cran-rlang-0.4.8/src/version.c 2020-10-07 10:44:44.000000000 +0000 +++ r-cran-rlang-0.4.10/src/version.c 2020-12-18 09:31:26.000000000 +0000 @@ -1,7 +1,7 @@ #define R_NO_REMAP #include -const char* rlang_version = "0.4.8"; +const char* rlang_version = "0.4.10"; /** * This file records the expected package version in the shared diff -Nru r-cran-rlang-0.4.8/tests/sink.R r-cran-rlang-0.4.10/tests/sink.R --- r-cran-rlang-0.4.8/tests/sink.R 2020-07-08 17:51:37.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/sink.R 2020-11-21 07:26:54.000000000 +0000 @@ -1,22 +1,6 @@ library(rlang) - -# `inform(file = )` tests cannot be performed with testthat because -# `message` conditions are muffled. - -# inform() prints to stdout by default in interactive sessions -local({ - file <- tempfile("inform-file-default") - do <- function() capture.output(inform("hello"), file = file) - - with_interactive(do(), value = FALSE) - stopifnot(identical(readLines(file), chr())) - - with_interactive(do()) - stopifnot(identical(readLines(file), "hello")) -}) - # inform() prints to file local({ file <- tempfile("inform-file-custom") diff -Nru r-cran-rlang-0.4.8/tests/testthat/fixtures/rlanglibtest/tests/testthat/test-quo-accessors.R r-cran-rlang-0.4.10/tests/testthat/fixtures/rlanglibtest/tests/testthat/test-quo-accessors.R --- r-cran-rlang-0.4.8/tests/testthat/fixtures/rlanglibtest/tests/testthat/test-quo-accessors.R 2018-09-22 09:55:57.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/fixtures/rlanglibtest/tests/testthat/test-quo-accessors.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("quo_accessors") - test_that("r_quo_get_expr() gets expression", { r_quo_get_expr <- function(quo) { .Call(rlanglibtest_r_quo_get_expr, quo) diff -Nru r-cran-rlang-0.4.8/tests/testthat/helper-cli.R r-cran-rlang-0.4.10/tests/testthat/helper-cli.R --- r-cran-rlang-0.4.8/tests/testthat/helper-cli.R 2019-03-15 15:52:40.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/helper-cli.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,6 +1,5 @@ -cli_style <- cli_box_chars() - -skip_unless_utf8 <- function() { - skip_if(!cli_is_utf8_output()) -} +cli_style <- with_options( + cli.unicode = FALSE, + cli_box_chars() +) diff -Nru r-cran-rlang-0.4.8/tests/testthat/helper-cnd.R r-cran-rlang-0.4.10/tests/testthat/helper-cnd.R --- r-cran-rlang-0.4.8/tests/testthat/helper-cnd.R 2019-06-12 18:25:13.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/helper-cnd.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,26 +1,5 @@ - -expect_condition <- function(expr, - class = NULL, - regex = NULL, - info = NULL, - label = NULL) { - object <- tryCatch(expr, condition = identity) - - if (is_na(class)) { - expect_false(inherits(object, "condition"), info = info, label = label) - return(invisible(object)) - } - - expect_is(object, "condition", info = info, label = label) - - if (!is_null(class)) { - expect_is(object, class, info = info, label = label) - } - if (!is_null(regex)) { - expect_match(object$message, regex, class, info = info, label = label) - } - - invisible(object) +cnd_cat <- function(x) { + cat(paste0(conditionMessage(x), "\n")) } expect_no_error <- function(...) { diff -Nru r-cran-rlang-0.4.8/tests/testthat/helper-locale.R r-cran-rlang-0.4.10/tests/testthat/helper-locale.R --- r-cran-rlang-0.4.8/tests/testthat/helper-locale.R 2019-06-13 11:39:48.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/helper-locale.R 2020-12-18 09:00:51.000000000 +0000 @@ -28,7 +28,15 @@ lang_strings$different[[1L]] } +local_utf8_test <- function(frame = caller_env()) { + reporter <- get_reporter() + old <- reporter$unicode + defer(reporter$unicode <- old, envir = frame) + reporter$unicode <- FALSE +} + with_non_utf8_locale <- function(code) { + local_utf8_test() old_locale <- mut_non_utf8_locale() on.exit(poke_ctype_locale(old_locale), add = TRUE) code @@ -46,6 +54,7 @@ } with_latin1_locale <- function(expr) { + local_utf8_test() old_locale <- suppressMessages(poke_latin1_locale()) on.exit(poke_ctype_locale(old_locale)) expr diff -Nru r-cran-rlang-0.4.8/tests/testthat/helper-output.R r-cran-rlang-0.4.10/tests/testthat/helper-output.R --- r-cran-rlang-0.4.8/tests/testthat/helper-output.R 2020-02-27 18:24:24.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/helper-output.R 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -# Dummy until implemented in testthat -verify_errors <- identity diff -Nru r-cran-rlang-0.4.8/tests/testthat/helper-rlang.R r-cran-rlang-0.4.10/tests/testthat/helper-rlang.R --- r-cran-rlang-0.4.8/tests/testthat/helper-rlang.R 2020-07-30 13:13:24.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/helper-rlang.R 2020-12-18 09:00:51.000000000 +0000 @@ -43,3 +43,22 @@ skip_if(has_stale_backtrace) } }) + +Rscript <- function(args, ...) { + out <- suppressWarnings(system2( + file.path(R.home("bin"), "Rscript"), + args, + ..., + stdout = TRUE, + stderr = TRUE + )) + + list( + out = unstructure(out), + status = attr(out, "status") + ) +} + +expect_reference <- function(object, expected) { + expect_true(is_reference(object, expected)) +} diff -Nru r-cran-rlang-0.4.8/tests/testthat/helper-trace.R r-cran-rlang-0.4.10/tests/testthat/helper-trace.R --- r-cran-rlang-0.4.8/tests/testthat/helper-trace.R 2020-01-17 18:31:06.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/helper-trace.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,14 +1,14 @@ -expect_known_trace_output <- function(trace, - file, - dir = normalizePath(test_path("..")), - srcrefs = FALSE) { - expect_known_output(file = test_path(file), { - cat("Full:\n") +expect_snapshot_trace <- function(trace, + file, + dir = normalizePath(test_path("..")), + srcrefs = FALSE) { + expect_snapshot({ + "Full" print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) - cat("\nCollapsed:\n") + "Collapsed" print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) - cat("\nBranch:\n") + "Branch" print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) }) } diff -Nru r-cran-rlang-0.4.8/tests/testthat/output-cnd-abort-parent-trace.txt r-cran-rlang-0.4.10/tests/testthat/output-cnd-abort-parent-trace.txt --- r-cran-rlang-0.4.8/tests/testthat/output-cnd-abort-parent-trace.txt 2020-10-07 08:39:52.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/output-cnd-abort-parent-trace.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -> parent <- TRUE -> wrapper <- FALSE -> err <- catch_cnd(f()) -> print(err) - -no wrapper -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() - -> wrapper <- TRUE -> err <- catch_cnd(f()) -> print(err) - -wrapper -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() - -> # FIXME? -> parent <- FALSE -> err <- catch_cnd(f()) -> print(err) - -wrapper -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() - - -withCallingHandlers() -===================== - -> print(err_wch) -x -+- -| bar -\- - foo -Backtrace: - 1. rlang::catch_cnd(...) - 9. rlang:::foo() - 10. rlang:::bar(cnd) - 11. rlang:::baz(cnd) - diff -Nru r-cran-rlang-0.4.8/tests/testthat/output-cnd-abort-trace-reminder.txt r-cran-rlang-0.4.10/tests/testthat/output-cnd-abort-trace-reminder.txt --- r-cran-rlang-0.4.8/tests/testthat/output-cnd-abort-trace-reminder.txt 2020-10-07 08:39:52.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/output-cnd-abort-trace-reminder.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -> # Normal case -> print(err) - -foo -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() - -> # From `last_error()` -> print(last_error()) - -foo -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() -Run `rlang::last_trace()` to see the full context. - -> # Saved from `last_error()` -> saved <- last_error() -> print(saved) - -foo -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() -Run `rlang::last_trace()` to see the full context. - -> # Saved from `last_error()`, but no longer last -> last_error_env$cnd <- error_cnd("foo") -> print(saved) - -foo -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() -Run `rlang::last_trace()` to see the full context. - diff -Nru r-cran-rlang-0.4.8/tests/testthat/_snaps/arg.md r-cran-rlang-0.4.10/tests/testthat/_snaps/arg.md --- r-cran-rlang-0.4.8/tests/testthat/_snaps/arg.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/_snaps/arg.md 2020-12-18 09:06:48.000000000 +0000 @@ -0,0 +1,45 @@ +# `arg_match()` has informative error messages + + Code + (expect_error(arg_match0("continuuos", c("discrete", "continuous")))) + Output + + `"continuuos"` must be one of "discrete" or "continuous". + Did you mean "continuous"? + Code + (expect_error(arg_match0("fou", c("bar", "foo")))) + Output + + `"fou"` must be one of "bar" or "foo". + Did you mean "foo"? + Code + (expect_error(arg_match0("fu", c("ba", "fo")))) + Output + + `"fu"` must be one of "ba" or "fo". + Did you mean "fo"? + Code + (expect_error(arg_match0("baq", c("foo", "baz", "bas"), arg_nm = "arg"))) + Output + + `arg` must be one of "foo", "baz", or "bas". + Did you mean "baz"? + Code + (expect_error(arg_match0("", character()))) + Output + + `values` must have at least one element. + +# `arg_match()` provides no suggestion when the edit distance is too large + + Code + (expect_error(arg_match0("foobaz", c("fooquxs", "discrete")))) + Output + + `"foobaz"` must be one of "fooquxs" or "discrete". + Code + (expect_error(arg_match0("a", c("b", "c")))) + Output + + `"a"` must be one of "b" or "c". + diff -Nru r-cran-rlang-0.4.8/tests/testthat/_snaps/cnd-abort.md r-cran-rlang-0.4.10/tests/testthat/_snaps/cnd-abort.md --- r-cran-rlang-0.4.8/tests/testthat/_snaps/cnd-abort.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/_snaps/cnd-abort.md 2020-12-18 09:07:01.000000000 +0000 @@ -0,0 +1,264 @@ +# error is printed with backtrace + + Code + cat_line(default_interactive) + Output + Error: Error message + Run `rlang::last_error()` to see where the error occurred. + Execution halted + Code + cat_line(default_non_interactive) + Output + Error: Error message + Backtrace: + x + 1. \-global::f() + 2. +-base::tryCatch(g()) + 3. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 4. \-global::g() + 5. \-global::h() + Execution halted + Code + cat_line(reminder) + Output + Error: Error message + + Execution halted + Code + cat_line(branch) + Output + Error: Error message + Backtrace: + 1. global::f() + 4. global::g() + 5. global::h() + Execution halted + Code + cat_line(collapse) + Output + Error: Error message + Backtrace: + x + 1. \-global::f() + 2. +-[ base::tryCatch(...) ] with 1 more call + 4. \-global::g() + 5. \-global::h() + Execution halted + Code + cat_line(full) + Output + Error: Error message + Backtrace: + x + 1. \-global::f() + 2. +-base::tryCatch(g()) + 3. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 4. \-global::g() + 5. \-global::h() + Execution halted + Code + cat_line(rethrown_interactive) + Output + Error: Error message + Run `rlang::last_error()` to see where the error occurred. + Execution halted + Code + cat_line(rethrown_non_interactive) + Output + Error: Error message + Backtrace: + x + 1. +-base::tryCatch(f(), error = function(cnd) rlang::cnd_signal(cnd)) + 2. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 3. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 4. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 5. \-global::f() + 6. +-base::tryCatch(g()) + 7. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 8. \-global::g() + 9. \-global::h() + Execution halted + +# empty backtraces are not printed + + Code + cat_line(branch_depth_0) + Output + Error: foo + + Execution halted + Code + cat_line(full_depth_0) + Output + Error: foo + + Execution halted + Code + cat_line(branch_depth_1) + Output + Error: foo + Backtrace: + 1. global::f() + Execution halted + Code + cat_line(full_depth_1) + Output + Error: foo + Backtrace: + x + 1. \-global::f() + Execution halted + +# parent errors are not displayed in error message and backtrace + + Code + cat_line(interactive) + Output + Error: bar + Run `rlang::last_error()` to see where the error occurred. + Execution halted + Code + cat_line(non_interactive) + Output + Error: bar + Backtrace: + x + 1. \-global::a() + 2. \-global::b() + 3. \-global::c() + 4. +-base::tryCatch(...) + 5. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 6. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 7. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 8. \-global::f() + 9. \-global::g() + 10. \-global::h() + Execution halted + +# backtrace reminder is displayed when called from `last_error()` + + Code + # Normal case + Code + print(err) + Output + + foo + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + Code + # From `last_error()` + Code + print(last_error()) + Output + + foo + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + Run `rlang::last_trace()` to see the full context. + Code + # Saved from `last_error()` + Code + { + saved <- last_error() + print(saved) + } + Output + + foo + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + Run `rlang::last_trace()` to see the full context. + Code + # Saved from `last_error()`, but no longer last + Code + { + last_error_env$cnd <- error_cnd("foo") + print(saved) + } + Output + + foo + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + Run `rlang::last_trace()` to see the full context. + +# capture context doesn't leak into low-level backtraces + + Code + # Non wrapped case + Code + { + parent <- TRUE + wrapper <- FALSE + err <- catch_cnd(f()) + print(err) + } + Output + + no wrapper + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + Code + # Wrapped case + Code + { + wrapper <- TRUE + err <- catch_cnd(f()) + print(err) + } + Output + + wrapper + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + Code + # FIXME? + Code + { + parent <- FALSE + err <- catch_cnd(f()) + print(err) + } + Output + + wrapper + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + Code + # withCallingHandlers() + Code + print(err_wch) + Output + x + +- + | bar + \- + foo + Backtrace: + 1. rlang::catch_cnd(...) + 9. rlang:::foo() + 10. rlang:::bar(cnd) + 11. rlang:::baz(cnd) + diff -Nru r-cran-rlang-0.4.8/tests/testthat/_snaps/cnd-entrace.md r-cran-rlang-0.4.10/tests/testthat/_snaps/cnd-entrace.md --- r-cran-rlang-0.4.8/tests/testthat/_snaps/cnd-entrace.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/_snaps/cnd-entrace.md 2020-12-18 09:07:02.000000000 +0000 @@ -0,0 +1,91 @@ +# with_abort() promotes base errors to rlang errors + + Code + print(err) + Output + x + +- + | High-level message + \- + Low-level message + Backtrace: + 1. base::identity(catch_cnd(a())) + 9. rlang:::a() + 10. rlang:::b() + 11. rlang:::c() + 18. rlang:::f() + 19. rlang:::g() + 20. rlang:::h() + Code + summary(err) + Output + x + +- + | High-level message + \- + Low-level message + Backtrace: + x + 1. +-base::identity(catch_cnd(a())) + 2. +-rlang::catch_cnd(a()) + 3. | +-rlang::eval_bare(...) + 4. | +-base::tryCatch(...) + 5. | | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 6. | | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 7. | | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 8. | \-base::force(expr) + 9. \-rlang:::a() + 10. \-rlang:::b() + 11. \-rlang:::c() + 12. +-base::tryCatch(...) + 13. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 14. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 15. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 16. +-rlang::with_abort(f()) + 17. | \-base::withCallingHandlers(...) + 18. \-rlang:::f() + 19. \-rlang:::g() + 20. \-rlang:::h() + +# rlang and base errors are properly entraced + + Code + cat_line(base) + Output + Error in h() : foo + Calls: f -> g -> h + Run `rlang::last_error()` to see where the error occurred. + + foo + Backtrace: + 1. global::f() + 2. global::g() + 3. global::h() + Run `rlang::last_trace()` to see the full context. + + foo + Backtrace: + █ + 1. └─global::f() + 2. └─global::g() + 3. └─global::h() + Code + cat_line(rlang) + Output + Error: foo + Run `rlang::last_error()` to see where the error occurred. + + foo + Backtrace: + 1. global::f() + 2. global::g() + 3. global::h() + Run `rlang::last_trace()` to see the full context. + + foo + Backtrace: + █ + 1. └─global::f() + 2. └─global::g() + 3. └─global::h() + diff -Nru r-cran-rlang-0.4.8/tests/testthat/_snaps/cnd-error.md r-cran-rlang-0.4.10/tests/testthat/_snaps/cnd-error.md --- r-cran-rlang-0.4.8/tests/testthat/_snaps/cnd-error.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/_snaps/cnd-error.md 2020-12-18 09:07:03.000000000 +0000 @@ -0,0 +1,210 @@ +# can use conditionMessage() method in subclasses of rlang errors + + Code + cat_line(interactive) + Output + Error: dispatched! + Run `rlang::last_error()` to see where the error occurred. + Execution halted + Code + cat_line(non_interactive) + Output + Error: dispatched! + Backtrace: + x + 1. \-global::f() + 2. \-global::g() + 3. \-global::h() + Execution halted + +# rlang_error.print() calls conditionMessage() method + + Code + print(err) + Output + + Low-level message + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + +# error is printed with parent backtrace + + Code + print(err) + Output + x + +- + | High-level message + \- + Backtrace: + 1. rlang::catch_cnd(a()) + 8. rlang:::a() + 9. rlang:::b() + 10. rlang:::c() + 15. rlang:::f() + 16. rlang:::g() + 17. rlang:::h() + Code + print(err_force) + Output + x + +- + | High-level message + \- + Low-level message + Backtrace: + 1. rlang::with_options(...) + 9. rlang:::a() + 10. rlang:::b() + 11. rlang:::c() + 16. rlang:::f() + 17. rlang:::g() + 18. rlang:::h() + +--- + + Code + print(err, simplify = "none") + Output + x + +- + | High-level message + \- + Backtrace: + x + 1. +-rlang::catch_cnd(a()) + 2. | +-rlang::eval_bare(...) + 3. | +-base::tryCatch(...) + 4. | | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 5. | | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 6. | | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 7. | \-base::force(expr) + 8. \-rlang:::a() + 9. \-rlang:::b() + 10. \-rlang:::c() + 11. +-base::tryCatch(...) + 12. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 13. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 14. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 15. \-rlang:::f() + 16. \-rlang:::g() + 17. \-rlang:::h() + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + +- + | High-level message + \- + Backtrace: + x + 1. +-rlang::catch_cnd(a()) + 2. | +-rlang::eval_bare(...) + 3. | +-base::tryCatch(...) + 4. | | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 5. | | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 6. | | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 7. | \-base::force(expr) + 8. \-rlang:::a() + 9. \-rlang:::b() + 10. \-rlang:::c() + 11. +-base::tryCatch(...) + 12. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 13. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 14. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 15. \-rlang:::f() + 16. \-rlang:::g() + 17. \-rlang:::h() + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + +- + | High-level message + \- + Backtrace: + x + 1. +-[ rlang::catch_cnd(...) ] with 6 more calls + 8. \-rlang:::a() + 9. \-rlang:::b() + 10. \-rlang:::c() + 11. +-[ base::tryCatch(...) ] with 3 more calls + 15. \-rlang:::f() + 16. \-rlang:::g() + 17. \-rlang:::h() + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + x + +- + | High-level message + \- + Backtrace: + 1. rlang::catch_cnd(a()) + 8. rlang:::a() + 9. rlang:::b() + 10. rlang:::c() + 15. rlang:::f() + 16. rlang:::g() + 17. rlang:::h() + +# summary.rlang_error() prints full backtrace + + Code + summary(err) + Output + x + +- + | The high-level error message + \- + The low-level error message + Backtrace: + x + 1. +-rlang::catch_cnd(a()) + 2. | +-rlang::eval_bare(...) + 3. | +-base::tryCatch(...) + 4. | | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 5. | | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 6. | | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 7. | \-base::force(expr) + 8. \-rlang:::a() + 9. +-base::tryCatch(b()) + 10. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 11. \-rlang:::b() + 12. \-rlang:::c() + 13. +-base::tryCatch(f(), error = handler) + 14. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 15. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 16. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 17. \-rlang:::f() + 18. +-base::tryCatch(g()) + 19. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 20. \-rlang:::g() + 21. \-rlang:::h() + +# don't print message or backtrace fields if empty + + Code + print(err) + Output + + +# base parent errors are printed with rlang method + + Code + print(rlang_err) + Output + + diff -Nru r-cran-rlang-0.4.8/tests/testthat/_snaps/cnd-signal.md r-cran-rlang-0.4.10/tests/testthat/_snaps/cnd-signal.md --- r-cran-rlang-0.4.8/tests/testthat/_snaps/cnd-signal.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/_snaps/cnd-signal.md 2020-12-18 09:07:05.000000000 +0000 @@ -0,0 +1,35 @@ +# cnd_signal() creates a backtrace if needed + + Code + print(err) + Output + + Backtrace: + 1. rlang::catch_cnd(f()) + 8. rlang:::f() + 9. rlang:::g() + 10. rlang:::h() + +# `inform()` and `warn()` with recurrent footer handle newlines correctly + + Code + inform("foo", .frequency = "regularly", .frequency_id = as.character(runif(1))) + Message + foo + This message is displayed once every 8 hours. + Code + inform("bar", .frequency = "regularly", .frequency_id = as.character(runif(1))) + Message + bar + This message is displayed once every 8 hours. + Code + warn("foo", .frequency = "regularly", .frequency_id = as.character(runif(1))) + Warning + foo + This warning is displayed once every 8 hours. + Code + warn("bar", .frequency = "regularly", .frequency_id = as.character(runif(1))) + Warning + bar + This warning is displayed once every 8 hours. + diff -Nru r-cran-rlang-0.4.8/tests/testthat/_snaps/env-special.md r-cran-rlang-0.4.10/tests/testthat/_snaps/env-special.md --- r-cran-rlang-0.4.8/tests/testthat/_snaps/env-special.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/_snaps/env-special.md 2020-12-18 09:07:08.000000000 +0000 @@ -0,0 +1,18 @@ +# check_installed() fails if packages are not installed + + Code + (expect_error(check_installed("_foo"))) + Output + + The `_foo` package is required. + Code + (expect_error(check_installed(c("_foo", "_bar")))) + Output + + The `_foo` and `_bar` packages are required. + Code + (expect_error(check_installed(c("_foo", "_bar"), "to proceed."))) + Output + + The `_foo` and `_bar` packages are required to proceed. + diff -Nru r-cran-rlang-0.4.8/tests/testthat/_snaps/operators.md r-cran-rlang-0.4.10/tests/testthat/_snaps/operators.md --- r-cran-rlang-0.4.8/tests/testthat/_snaps/operators.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/_snaps/operators.md 2020-12-18 09:07:14.000000000 +0000 @@ -0,0 +1,41 @@ +# %|% fails with wrong types + + Code + (expect_error(c(1L, NA) %|% 2)) + Output + + Replacement values must have type integer, not type double + Code + (expect_error(c(1, NA) %|% "")) + Output + + Replacement values must have type double, not type character + Code + (expect_error(c(1, NA) %|% call("fn"))) + Output + + Replacement values must have type double, not type language + Code + (expect_error(call("fn") %|% 1)) + Output + + Cannot replace missing values in an object of type language + +# %|% fails with wrong length + + Code + (expect_error(c(1L, NA) %|% 1:3)) + Output + + The replacement values must have size 1 or 2, not 3 + Code + (expect_error(1:10 %|% 1:4)) + Output + + The replacement values must have size 1 or 10, not 4 + Code + (expect_error(1L %|% 1:4)) + Output + + The replacement values must have size 1, not 4 + diff -Nru r-cran-rlang-0.4.8/tests/testthat/_snaps/trace.md r-cran-rlang-0.4.10/tests/testthat/_snaps/trace.md --- r-cran-rlang-0.4.8/tests/testthat/_snaps/trace.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/_snaps/trace.md 2020-12-18 09:07:24.000000000 +0000 @@ -0,0 +1,1056 @@ +# tree printing only changes deliberately + + Code + print(trace, dir = dir) + Output + x + 1. \-rlang:::i() test-trace.R:26:2 + 2. \-rlang:::j(i) test-trace.R:19:7 + 3. \-rlang:::k(i) test-trace.R:20:21 + 4. \-rlang:::l(i) test-trace.R:23:4 + Code + cat("\n") + Output + + Code + print(trace_subset(trace, 0L), dir = dir) + Output + x + +# can print tree with collapsed branches + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. \-rlang:::g() test-trace.R:51:20 + 3. +-base::tryCatch(h(), foo = identity, bar = identity) test-trace.R:52:20 + 4. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 5. | +-base:::tryCatchOne(...) + 6. | | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 7. | \-base:::tryCatchList(expr, names[-nh], parentenv, handlers[-nh]) + 8. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 9. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 10. \-rlang:::h() + 11. +-base::tryCatch(i(), baz = identity) test-trace.R:53:20 + 12. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 13. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 14. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 15. \-rlang:::i() + 16. +-base::tryCatch(trace_back(e, bottom = 0)) test-trace.R:54:20 + 17. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 18. \-rlang::trace_back(e, bottom = 0) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. \-rlang:::g() test-trace.R:51:20 + 3. +-[ base::tryCatch(...) ] with 6 more calls test-trace.R:52:20 + 10. \-rlang:::h() + 11. +-[ base::tryCatch(...) ] with 3 more calls test-trace.R:53:20 + 15. \-rlang:::i() + 16. +-[ base::tryCatch(...) ] with 1 more call test-trace.R:54:20 + 18. \-rlang::trace_back(e, bottom = 0) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::f() + 2. rlang:::g() test-trace.R:51:20 + 10. rlang:::h() + 15. rlang:::i() + 18. rlang::trace_back(e, bottom = 0) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. +-base::eval(quote(eval(quote(g())))) test-trace.R:64:7 + 3. | \-base::eval(quote(eval(quote(g())))) + 4. +-base::eval(quote(g())) + 5. | \-base::eval(quote(g())) + 6. \-rlang:::g() + 7. +-base::tryCatch(eval(quote(h())), foo = identity, bar = identity) test-trace.R:65:7 + 8. | \-base:::tryCatchList(expr, classes, parentenv, handlers) + 9. | +-base:::tryCatchOne(...) + 10. | | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 11. | \-base:::tryCatchList(expr, names[-nh], parentenv, handlers[-nh]) + 12. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) + 13. | \-base:::doTryCatch(return(expr), name, parentenv, handler) + 14. +-base::eval(quote(h())) + 15. | \-base::eval(quote(h())) + 16. \-rlang:::h() + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. +-[ base::eval(...) ] with 1 more call test-trace.R:64:7 + 4. +-[ base::eval(...) ] with 1 more call + 6. \-rlang:::g() + 7. +-[ base::tryCatch(...) ] with 6 more calls test-trace.R:65:7 + 14. +-[ base::eval(...) ] with 1 more call + 16. \-rlang:::h() + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::f() + 6. rlang:::g() + 16. rlang:::h() + +# recursive frames are rewired to the global env + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-rlang::eval_tidy(quo(f())) + 2. \-rlang:::f() + 3. \-rlang:::g() + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ rlang::eval_tidy(...) ] + 2. \-rlang:::f() + 3. \-rlang:::g() + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang::eval_tidy(quo(f())) + 2. rlang:::f() + 3. rlang:::g() + +# long backtrace branches are truncated + + Code + cat("Full:\n") + Output + Full: + Code + print(trace, simplify = "branch", srcrefs = FALSE) + Output + 1. rlang:::f(10) + 2. rlang:::f(n - 1) + 3. rlang:::f(n - 1) + 4. rlang:::f(n - 1) + 5. rlang:::f(n - 1) + 6. rlang:::f(n - 1) + 7. rlang:::f(n - 1) + 8. rlang:::f(n - 1) + 9. rlang:::f(n - 1) + 10. rlang:::f(n - 1) + 11. rlang:::f(n - 1) + Code + cat("\n5 frames:\n") + Output + + 5 frames: + Code + print(trace, simplify = "branch", max_frames = 5, srcrefs = FALSE) + Output + 1. rlang:::f(10) + 2. rlang:::f(n - 1) + 3. rlang:::f(n - 1) + ... + 10. rlang:::f(n - 1) + 11. rlang:::f(n - 1) + Code + cat("\n2 frames:\n") + Output + + 2 frames: + Code + print(trace, simplify = "branch", max_frames = 2, srcrefs = FALSE) + Output + 1. rlang:::f(10) + ... + 11. rlang:::f(n - 1) + Code + cat("\n1 frame:\n") + Output + + 1 frame: + Code + print(trace, simplify = "branch", max_frames = 1, srcrefs = FALSE) + Output + 1. rlang:::f(10) + ... + +# eval() frames are collapsed + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. +-base::eval(quote(g())) + 3. | \-base::eval(quote(g())) + 4. \-rlang:::g() + 5. +-base::eval(quote(trace_back(e, bottom = 0))) + 6. | \-base::eval(quote(trace_back(e, bottom = 0))) + 7. \-rlang::trace_back(e, bottom = 0) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. +-[ base::eval(...) ] with 1 more call + 4. \-rlang:::g() + 5. +-[ base::eval(...) ] with 1 more call + 7. \-rlang::trace_back(e, bottom = 0) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::f() + 4. rlang:::g() + 7. rlang::trace_back(e, bottom = 0) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. +-base::evalq(g()) + 3. | \-base::evalq(g()) + 4. \-rlang:::g() + 5. +-base::evalq(trace_back(e, bottom = 0)) + 6. | \-base::evalq(trace_back(e, bottom = 0)) + 7. \-rlang::trace_back(e, bottom = 0) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. +-[ base::evalq(...) ] with 1 more call + 4. \-rlang:::g() + 5. +-[ base::evalq(...) ] with 1 more call + 7. \-rlang::trace_back(e, bottom = 0) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::f() + 4. rlang:::g() + 7. rlang::trace_back(e, bottom = 0) + +# %>% frames are collapsed + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-NULL %>% f() %>% g(1, 2) %>% h(3, ., 4) + 2. \-rlang:::h(3, ., 4) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ NULL %>% f() %>% g(1, 2) %>% h(3, ., 4) ] + 2. \-rlang:::h(3, ., 4) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. NULL %>% f() %>% g(1, 2) %>% h(3, ., 4) + 2. rlang:::h(3, ., 4) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-f(NULL) %>% g(list(.)) %>% h(3, ., list(.)) + 2. \-rlang:::h(3, ., list(.)) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ f(NULL) %>% g(list(.)) %>% h(3, ., list(.)) ] + 2. \-rlang:::h(3, ., list(.)) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. f(NULL) %>% g(list(.)) %>% h(3, ., list(.)) + 2. rlang:::h(3, ., list(.)) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-rlang:::f(g(NULL %>% f()) %>% h()) + 2. +-g(NULL %>% f()) %>% h() + 3. \-rlang:::h(.) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ rlang:::f(...) ] + 2. +-[ g(NULL %>% f()) %>% h() ] + 3. \-rlang:::h(.) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::f(g(NULL %>% f()) %>% h()) + 3. rlang:::h(.) + +# children of collapsed %>% frames have correct parent + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-NA %>% F() %>% G() %>% H() + 2. \-rlang:::H(.) + 3. \-rlang:::f() + 4. \-rlang:::h() + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ NA %>% F() %>% G() %>% H() ] + 2. \-rlang:::H(.) + 3. \-rlang:::f() + 4. \-rlang:::h() + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. NA %>% F() %>% G() %>% H() + 2. rlang:::H(.) + 3. rlang:::f() + 4. rlang:::h() + +# children of collapsed frames are rechained to correct parent + + Code + cat("Full:\n") + Output + Full: + Code + print(trace, simplify = "none", srcrefs = FALSE) + Output + x + 1. \-rlang:::f() + 2. \-base::eval(quote(g()), env()) + 3. \-base::eval(quote(g()), env()) + 4. \-rlang:::g() + Code + cat("\nCollapsed:\n") + Output + + Collapsed: + Code + print(trace, simplify = "collapse", srcrefs = FALSE) + Output + x + 1. \-rlang:::f() + 2. \-[ base::eval(...) ] with 1 more call + 4. \-rlang:::g() + Code + cat("\nBranch:\n") + Output + + Branch: + Code + print(trace, simplify = "branch", srcrefs = FALSE) + Output + 1. rlang:::f() + 2. [ base::eval(...) ] with 1 more call + 4. rlang:::g() + +# combinations of incomplete and leading pipes collapse properly + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-NA %>% F() %>% T() %>% F() %>% F() + 2. +-rlang:::F(.) + 3. +-rlang:::F(.) + 4. \-rlang:::T(.) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ NA %>% F() %>% T() %>% F() %>% F() ] + 2. +-[ rlang:::F(...) ] + 3. +-[ rlang:::F(...) ] + 4. \-rlang:::T(.) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. NA %>% F() %>% T() %>% F() %>% F() + 4. rlang:::T(.) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-T(NA) %>% F() + 2. +-rlang:::F(.) + 3. \-rlang:::T(NA) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ T(NA) %>% F() ] + 2. +-[ rlang:::F(...) ] + 3. \-rlang:::T(NA) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. T(NA) %>% F() + 3. rlang:::T(NA) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-F(NA) %>% F() %>% T() %>% F() %>% F() + 2. +-rlang:::F(.) + 3. +-rlang:::F(.) + 4. \-rlang:::T(.) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ F(NA) %>% F() %>% T() %>% F() %>% F() ] + 2. +-[ rlang:::F(...) ] + 3. +-[ rlang:::F(...) ] + 4. \-rlang:::T(.) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. F(NA) %>% F() %>% T() %>% F() %>% F() + 4. rlang:::T(.) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-NA %>% T() + 2. \-rlang:::T(.) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ NA %>% T() ] + 2. \-rlang:::T(.) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. NA %>% T() + 2. rlang:::T(.) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-NA %>% F() %>% T() + 2. \-rlang:::T(.) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ NA %>% F() %>% T() ] + 2. \-rlang:::T(.) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. NA %>% F() %>% T() + 2. rlang:::T(.) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-F(NA) %>% T() + 2. \-rlang:::T(.) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ F(NA) %>% T() ] + 2. \-rlang:::T(.) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. F(NA) %>% T() + 2. rlang:::T(.) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-F(NA) %>% F() %>% T() + 2. \-rlang:::T(.) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ F(NA) %>% F() %>% T() ] + 2. \-rlang:::T(.) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. F(NA) %>% F() %>% T() + 2. rlang:::T(.) + +# calls before and after pipe are preserved + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-rlang:::F(NA %>% T()) + 2. +-NA %>% T() + 3. \-rlang:::T(.) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ rlang:::F(...) ] + 2. +-[ NA %>% T() ] + 3. \-rlang:::T(.) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::F(NA %>% T()) + 3. rlang:::T(.) + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-NA %>% C() + 2. \-rlang:::C(.) + 3. \-rlang:::f() + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ NA %>% C() ] + 2. \-rlang:::C(.) + 3. \-rlang:::f() + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. NA %>% C() + 2. rlang:::C(.) + 3. rlang:::f() + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-rlang:::F(NA %>% C()) + 2. +-NA %>% C() + 3. \-rlang:::C(.) + 4. \-rlang:::f() + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ rlang:::F(...) ] + 2. +-[ NA %>% C() ] + 3. \-rlang:::C(.) + 4. \-rlang:::f() + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::F(NA %>% C()) + 3. rlang:::C(.) + 4. rlang:::f() + +# always keep very first frame as part of backtrace branch + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-rlang:::gen() + 2. \-rlang:::gen.default() + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ rlang:::gen() ] + 2. \-rlang:::gen.default() + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::gen() + 2. rlang:::gen.default() + +# anonymous calls are stripped from backtraces + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-(function() {... + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-(function() {... + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + + +# collapsing of eval() frames detects when error occurs within eval() + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-base::eval() + 2. \-base::.handleSimpleError(...) + 3. \-rlang:::h(simpleError(msg, call)) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ base::eval() ] + 2. \-base::.handleSimpleError(...) + 3. \-rlang:::h(simpleError(msg, call)) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. base::eval() + 2. base::.handleSimpleError(...) + 3. rlang:::h(simpleError(msg, call)) + +# can print degenerate backtraces + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-foo + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-foo + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. foo + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-NULL + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-NULL + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. NULL + +--- + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-1L + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-1L + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. 1L + +# check for dangling promise in call CAR (#492) + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-base::print(foo) + 2. \-rlang:::print.foo(foo) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. +-[ base::print(...) ] + 2. \-rlang:::print.foo(foo) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. base::print(foo) + 2. rlang:::print.foo(foo) + +# dangling srcrefs are not printed + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f(current_env()) + 2. \-rlang:::g(e) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f(current_env()) + 2. \-rlang:::g(e) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::f(current_env()) + 2. rlang:::g(e) + +# summary.rlang_trace() prints the full tree + + Code + summary(trace, srcrefs = FALSE) + Output + x + 1. \-rlang:::f() + 2. \-rlang:::g() + 3. \-rlang:::h() + +# unexported functions have `:::` prefix + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. \-rlanglibtest:::test_trace_unexported_child(e) + 3. \-rlanglibtest:::test_trace_unexported(e) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::f() + 2. \-rlanglibtest:::test_trace_unexported_child(e) + 3. \-rlanglibtest:::test_trace_unexported(e) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::f() + 2. rlanglibtest:::test_trace_unexported_child(e) + 3. rlanglibtest:::test_trace_unexported(e) + +# global functions have `global::` prefix + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::g(current_env()) + 2. \-global::f(e) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::g(current_env()) + 2. \-global::f(e) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::g(current_env()) + 2. global::f(e) + +# local functions inheriting from global do not have `global::` prefix + + Code + # Full + Code + print(trace, simplify = "none", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::g(current_env()) + 2. \-f(e) + Code + # Collapsed + Code + print(trace, simplify = "collapse", dir = dir, srcrefs = srcrefs) + Output + x + 1. \-rlang:::g(current_env()) + 2. \-f(e) + Code + # Branch + Code + print(trace, simplify = "branch", dir = dir, srcrefs = srcrefs) + Output + 1. rlang:::g(current_env()) + 2. f(e) + +# can trim layers of backtraces + + Code + local_options(rlang_trace_format_srcrefs = FALSE) + Code + cat_line("No trimming:") + Output + No trimming: + Code + summary(trace0) + Output + x + 1. \-rlang:::f(0) test-trace.R:482:2 + 2. +-base::identity(identity(g(n))) test-trace.R:478:7 + 3. +-base::identity(g(n)) + 4. \-rlang:::g(n) + 5. +-base::identity(identity(h(n))) test-trace.R:479:7 + 6. +-base::identity(h(n)) + 7. \-rlang:::h(n) + 8. +-base::identity(identity(trace_back(e, bottom = n))) test-trace.R:480:7 + 9. +-base::identity(trace_back(e, bottom = n)) + 10. \-rlang::trace_back(e, bottom = n) + Code + cat_line("", "", "One layer (the default):") + Output + + + One layer (the default): + Code + summary(trace1) + Output + x + 1. \-rlang:::f(1) test-trace.R:483:2 + 2. +-base::identity(identity(g(n))) test-trace.R:478:7 + 3. +-base::identity(g(n)) + 4. \-rlang:::g(n) + 5. +-base::identity(identity(h(n))) test-trace.R:479:7 + 6. +-base::identity(h(n)) + 7. \-rlang:::h(n) + Code + cat_line("", "", "Two layers:") + Output + + + Two layers: + Code + summary(trace2) + Output + x + 1. \-rlang:::f(2) test-trace.R:484:2 + 2. +-base::identity(identity(g(n))) test-trace.R:478:7 + 3. +-base::identity(g(n)) + 4. \-rlang:::g(n) + Code + cat_line("", "", "Three layers:") + Output + + + Three layers: + Code + summary(trace3) + Output + x + 1. \-rlang:::f(3) test-trace.R:485:2 + diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-arg.R r-cran-rlang-0.4.10/tests/testthat/test-arg.R --- r-cran-rlang-0.4.8/tests/testthat/test-arg.R 2020-07-07 14:33:41.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-arg.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("arg") - test_that("matches arg", { myarg <- "foo" expect_identical(arg_match0(myarg, c("bar", "foo")), "foo") @@ -52,34 +50,30 @@ ) }) -test_that("informative error message on a typo", { - verify_output("test-typo-suggest.txt", { - myarg <- "continuuos" - arg_match0(myarg, c("discrete", "continuous")) - myarg <- "fou" - arg_match0(myarg, c("bar", "foo")) - myarg <- "fu" - arg_match0(myarg, c("ba", "fo")) - - "# No suggestion when the edit distance is too large" - myarg <- "foobaz" - arg_match0(myarg, c("fooquxs", "discrete")) - myarg <- "a" - arg_match0(myarg, c("b", "c")) - - "# Even with small possible typos, if there's a match it returns the match" - myarg <- "bas" - arg_match0(myarg, c("foo", "baz", "bas")) - - "# arg_nm is honored" - myarg <- "baq" - arg_match0(myarg, c("foo", "baz", "bas"), arg_nm = "arg") +test_that("`arg_match()` has informative error messages", { + expect_snapshot({ + (expect_error(arg_match0("continuuos", c("discrete", "continuous")))) + (expect_error(arg_match0("fou", c("bar", "foo")))) + (expect_error(arg_match0("fu", c("ba", "fo")))) + (expect_error(arg_match0("baq", c("foo", "baz", "bas"), arg_nm = "arg"))) + (expect_error(arg_match0("", character()))) + }) +}) - "# Corner case" - arg_match0("", character()) +test_that("`arg_match()` provides no suggestion when the edit distance is too large", { + expect_snapshot({ + (expect_error(arg_match0("foobaz", c("fooquxs", "discrete")))) + (expect_error(arg_match0("a", c("b", "c")))) }) }) +test_that("`arg_match()` finds a match even with small possible typos", { + expect_equal( + arg_match0("bas", c("foo", "baz", "bas")), + "bas" + ) +}) + test_that("gets choices from function", { fn <- function(myarg = c("bar", "foo")) { arg_match(myarg) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-attr.R r-cran-rlang-0.4.10/tests/testthat/test-attr.R --- r-cran-rlang-0.4.8/tests/testthat/test-attr.R 2020-02-27 18:24:24.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-attr.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("attributes") - test_that("names2() takes care of missing values", { x <- set_names(1:3, c("a", NA, "b")) expect_identical(names2(x), c("a", "", "b")) @@ -60,3 +58,57 @@ chr <- c("a", b = "B", "c") expect_equal(set_names2(chr), c(a = "a", b = "B", c = "c")) }) + +test_that("zap_srcref() removes source references", { + with_srcref("x <- quote({ NULL })") + expect_null(attributes(zap_srcref(x))) +}) + +test_that("zap_srcref() handles nested functions (r-lib/testthat#1228)", { + with_srcref(" + factory <- function() { + function() { + function() { + 1 + } + } + }" + ) + + fn <- zap_srcref(factory()) + expect_null(attributes(fn)) + + curly <- body(fn) + expect_null(attributes(curly)) + + fn_call <- curly[[2]] + expect_null(attributes(fn_call)) + + # Calls to `function` store srcrefs in 4th cell + expect_length(fn_call, 3) + + # Can call `zap_srcref()` repeatedly + expect_equal( + zap_srcref(fn), + fn + ) +}) + +test_that("zap_srcref() works with quosures", { + with_srcref("x <- expr({ !!quo({ NULL }) })") + + out <- zap_srcref(x) + expect_null(attributes(out)) + + quo <- out[[2]] + expect_null(attributes(quo_get_expr(quo))) +}) + +test_that("can zap_srcref() on functions with `[[` methods", { + local_methods( + `[[.rlang:::not_subsettable` = function(...) stop("Can't subset!"), + `[[<-.rlang:::not_subsettable` = function(...) stop("Can't subset!") + ) + fn <- structure(quote(function() NULL), class = "rlang:::not_subsettable") + expect_error(zap_srcref(fn), NA) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-call.R r-cran-rlang-0.4.10/tests/testthat/test-call.R --- r-cran-rlang-0.4.8/tests/testthat/test-call.R 2019-10-23 08:50:38.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-call.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("call") - # Creation ---------------------------------------------------------------- test_that("character vector must be length 1", { @@ -21,8 +19,8 @@ }) test_that("succeeds with literal functions", { - expect_error(regex = NA, call2(base::mean, 1:10)) - expect_error(regex = NA, call2(base::list, 1:10)) + expect_error(regexp = NA, call2(base::mean, 1:10)) + expect_error(regexp = NA, call2(base::list, 1:10)) }) test_that("call2() preserves empty arguments", { diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-c-api.R r-cran-rlang-0.4.10/tests/testthat/test-c-api.R --- r-cran-rlang-0.4.8/tests/testthat/test-c-api.R 2020-08-12 09:15:35.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-c-api.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("C API") - r_string <- function(str) { stopifnot(is_string(str)) .Call(rlang_r_string, str) @@ -94,6 +92,8 @@ expect_identical(call_parse_type(quote(for (a in b) b)), "for") expect_identical(call_parse_type(quote(repeat a)), "repeat") expect_identical(call_parse_type(quote(if (a) b)), "if") + expect_identical(call_parse_type(quote(break)), "break") + expect_identical(call_parse_type(quote(next)), "next") expect_identical(call_parse_type(quote(a <- b)), "<-") expect_identical(call_parse_type(quote(a <<- b)), "<<-") diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-abort.R r-cran-rlang-0.4.10/tests/testthat/test-cnd-abort.R --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-abort.R 2020-07-29 15:30:05.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-abort.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,9 +1,7 @@ -context("cnd-abort") - test_that("errors are signalled with backtrace", { fn <- function() abort("") err <- catch_cnd(fn()) - expect_is(err$trace, "rlang_trace") + expect_s3_class(err$trace, "rlang_trace") }) test_that("can pass classed strings as error message", { @@ -68,7 +66,6 @@ }) test_that("error is printed with backtrace", { - skip_unless_utf8() skip_if_stale_backtrace() run_error_script <- function(envvars = chr()) { @@ -90,63 +87,39 @@ test_path("fixtures", "error-backtrace-rethrown.R") ) - verify_output(test_path("test-cnd-error.txt"), { - "Default (interactive)" + expect_snapshot({ cat_line(default_interactive) - - "Default (non-interactive)" cat_line(default_non_interactive) - - "Reminder" cat_line(reminder) - - "Branch" cat_line(branch) - - "Collapse" cat_line(collapse) - - "Full" cat_line(full) - - "Rethrown (interactive)" cat_line(rethrown_interactive) - - "Rethrown (non-interactive)" cat_line(rethrown_non_interactive) }) }) test_that("empty backtraces are not printed", { - skip_unless_utf8() skip_if_stale_backtrace() run_error_script <- function(envvars = chr()) { run_script(test_path("fixtures", "error-backtrace-empty.R"), envvars = envvars) } - branch0 <- run_error_script(envvars = c("rlang_backtrace_on_error=branch", "trace_depth=0")) - full0 <- run_error_script(envvars = c("rlang_backtrace_on_error=full", "trace_depth=0")) - branch1 <- run_error_script(envvars = c("rlang_backtrace_on_error=branch", "trace_depth=1")) - full1 <- run_error_script(envvars = c("rlang_backtrace_on_error=full", "trace_depth=1")) - - verify_output(test_path("test-cnd-error-empty.txt"), { - "Branch (depth 0)" - cat_line(branch0) - - "Full" - cat_line(full0) - - "Branch (depth 1)" - cat_line(branch1) - - "Full (depth 1)" - cat_line(full1) + branch_depth_0 <- run_error_script(envvars = c("rlang_backtrace_on_error=branch", "trace_depth=0")) + full_depth_0 <- run_error_script(envvars = c("rlang_backtrace_on_error=full", "trace_depth=0")) + branch_depth_1 <- run_error_script(envvars = c("rlang_backtrace_on_error=branch", "trace_depth=1")) + full_depth_1 <- run_error_script(envvars = c("rlang_backtrace_on_error=full", "trace_depth=1")) + + expect_snapshot({ + cat_line(branch_depth_0) + cat_line(full_depth_0) + cat_line(branch_depth_1) + cat_line(full_depth_1) }) }) test_that("parent errors are not displayed in error message and backtrace", { - skip_unless_utf8() skip_if_stale_backtrace() run_error_script <- function(envvars = chr()) { @@ -158,11 +131,8 @@ non_interactive <- run_error_script() interactive <- run_error_script(envvars = "rlang_interactive=true") - verify_output(test_path("test-cnd-error-parent.txt"), { - "Interactive" + expect_snapshot({ cat_line(interactive) - - "Non-interactive" cat_line(non_interactive) }) }) @@ -180,7 +150,7 @@ last_error_env$cnd <- err - verify_output(test_path("output-cnd-abort-trace-reminder.txt"), { + expect_snapshot({ "Normal case" print(err) @@ -188,12 +158,16 @@ print(last_error()) "Saved from `last_error()`" - saved <- last_error() - print(saved) + { + saved <- last_error() + print(saved) + } "Saved from `last_error()`, but no longer last" - last_error_env$cnd <- error_cnd("foo") - print(saved) + { + last_error_env$cnd <- error_cnd("foo") + print(saved) + } }) }) @@ -233,22 +207,30 @@ ) ) - verify_output(test_path("output-cnd-abort-parent-trace.txt"), { - parent <- TRUE - wrapper <- FALSE - err <- catch_cnd(f()) - print(err) + expect_snapshot({ + "Non wrapped case" + { + parent <- TRUE + wrapper <- FALSE + err <- catch_cnd(f()) + print(err) + } - wrapper <- TRUE - err <- catch_cnd(f()) - print(err) + "Wrapped case" + { + wrapper <- TRUE + err <- catch_cnd(f()) + print(err) + } "FIXME?" - parent <- FALSE - err <- catch_cnd(f()) - print(err) + { + parent <- FALSE + err <- catch_cnd(f()) + print(err) + } - "# withCallingHandlers()" + "withCallingHandlers()" print(err_wch) }) }) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-entrace.R r-cran-rlang-0.4.10/tests/testthat/test-cnd-entrace.R --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-entrace.R 2020-07-30 13:17:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-entrace.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,8 +1,4 @@ -context("cnd-entrace") - test_that("with_abort() promotes base errors to rlang errors", { - skip_unless_utf8() - f <- function() g() g <- function() h() h <- function() stop("Low-level message") @@ -24,11 +20,9 @@ ) err <- identity(catch_cnd(a())) - expect_known_output(file = test_path("test-with-abort.txt"), { - cat_line("print():", "") + expect_snapshot({ print(err) - cat_line("", "", "summary():", "") summary(err) }) }) @@ -47,7 +41,7 @@ native = NULL, classes = "error") { err <- catch_abort(signaller, arg, classes = classes) - expect_is(err, "rlang_error") + expect_s3_class(err, "rlang_error") trace <- err$trace n <- trace_length(err$trace) @@ -79,7 +73,7 @@ expect_true(inherits_all(msg, c("message", "condition"))) err <- catch_abort(base::message, "", classes = "message") - expect_is(err, "rlang_error") + expect_s3_class(err, "rlang_error") expect_abort_trace(base::stop, "") expect_abort_trace(base::stop, cnd("error")) @@ -175,11 +169,27 @@ envvars = "rlang_error_kind=rlang" ) - verify_output(test_path("test-entrace.txt"), { - "# base error" + expect_snapshot({ cat_line(base) - - "# rlang error" cat_line(rlang) }) }) + +test_that("entrace() preserves exit status in non-interactive sessions (#1052, rstudio/bookdown#920)", { + # Probably because of + skip_if(getRversion() < "3.3") + + out <- Rscript(shQuote(c("--vanilla", "-e", 'options(error = rlang::entrace); stop("An error")'))) + expect_false(out$status == 0L) + + code <- ' + { + options(error = rlang::entrace) + f <- function() g() + g <- function() h() + h <- function() stop("An error") + f() + }' + out <- Rscript(shQuote(c("--vanilla", "-e", code))) + expect_false(out$status == 0L) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-conditionMessage.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-conditionMessage.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-conditionMessage.txt 2020-10-07 08:39:54.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-conditionMessage.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -> # Interactive -> cat_line(interactive) -Error: dispatched! -Run `rlang::last_error()` to see where the error occurred. -Execution halted - -> # Non-interactive -> cat_line(non_interactive) -Error: dispatched! -Backtrace: - x - 1. \-global::f() - 2. \-global::g() - 3. \-global::h() -Execution halted - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-empty.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-empty.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-empty.txt 2020-10-07 08:39:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-empty.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -> # Branch (depth 0) -> cat_line(branch0) -Error: foo - -Execution halted - -> # Full -> cat_line(full0) -Error: foo - -Execution halted - -> # Branch (depth 1) -> cat_line(branch1) -Error: foo -Backtrace: - 1. global::f() -Execution halted - -> # Full (depth 1) -> cat_line(full1) -Error: foo -Backtrace: - x - 1. \-global::f() -Execution halted - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-parent-default.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-parent-default.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-parent-default.txt 2020-10-07 08:39:55.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-parent-default.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -█ -├─ -│ High-level message -└─ -Backtrace: - 1. rlang::catch_cnd(a()) - 8. rlang:::a() - 9. rlang:::b() - 10. rlang:::c() - 15. rlang:::f() - 16. rlang:::g() - 17. rlang:::h() -█ -├─ -│ High-level message -└─ - Low-level message -Backtrace: - 1. rlang::with_options(...) - 9. rlang:::a() - 10. rlang:::b() - 11. rlang:::c() - 16. rlang:::f() - 17. rlang:::g() - 18. rlang:::h() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-parent-full.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-parent-full.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-parent-full.txt 2020-10-07 08:39:55.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-parent-full.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -█ -├─ -│ High-level message -└─ -Backtrace: - █ - 1. ├─rlang::catch_cnd(a()) - 2. │ ├─rlang::eval_bare(...) - 3. │ ├─base::tryCatch(...) - 4. │ │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 5. │ │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 6. │ │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 7. │ └─base::force(expr) - 8. └─rlang:::a() - 9. └─rlang:::b() - 10. └─rlang:::c() - 11. ├─base::tryCatch(...) - 12. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 13. │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 14. │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 15. └─rlang:::f() - 16. └─rlang:::g() - 17. └─rlang:::h() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-parent-trace.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-parent-trace.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-parent-trace.txt 2020-10-07 08:39:55.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-parent-trace.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -Full: -█ -├─ -│ High-level message -└─ -Backtrace: - █ - 1. ├─rlang::catch_cnd(a()) - 2. │ ├─rlang::eval_bare(...) - 3. │ ├─base::tryCatch(...) - 4. │ │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 5. │ │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 6. │ │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 7. │ └─base::force(expr) - 8. └─rlang:::a() - 9. └─rlang:::b() - 10. └─rlang:::c() - 11. ├─base::tryCatch(...) - 12. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 13. │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 14. │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 15. └─rlang:::f() - 16. └─rlang:::g() - 17. └─rlang:::h() - -Collapsed: -█ -├─ -│ High-level message -└─ -Backtrace: - █ - 1. ├─[ rlang::catch_cnd(...) ] with 6 more calls - 8. └─rlang:::a() - 9. └─rlang:::b() - 10. └─rlang:::c() - 11. ├─[ base::tryCatch(...) ] with 3 more calls - 15. └─rlang:::f() - 16. └─rlang:::g() - 17. └─rlang:::h() - -Branch: -█ -├─ -│ High-level message -└─ -Backtrace: - 1. rlang::catch_cnd(a()) - 8. rlang:::a() - 9. rlang:::b() - 10. rlang:::c() - 15. rlang:::f() - 16. rlang:::g() - 17. rlang:::h() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-parent.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-parent.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-parent.txt 2020-10-07 08:39:52.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-parent.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -> # Interactive -> cat_line(interactive) -Error: bar -Run `rlang::last_error()` to see where the error occurred. -Execution halted - -> # Non-interactive -> cat_line(non_interactive) -Error: bar -Backtrace: - x - 1. \-global::a() - 2. \-global::b() - 3. \-global::c() - 4. +-base::tryCatch(...) - 5. | \-base:::tryCatchList(expr, classes, parentenv, handlers) - 6. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 7. | \-base:::doTryCatch(return(expr), name, parentenv, handler) - 8. \-global::f() - 9. \-global::g() - 10. \-global::h() -Execution halted - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-print-base-parent.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-print-base-parent.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-print-base-parent.txt 2020-10-07 08:39:55.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-print-base-parent.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-print-no-message.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-print-no-message.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-print-no-message.txt 2020-10-07 08:39:55.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-print-no-message.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error.R r-cran-rlang-0.4.10/tests/testthat/test-cnd-error.R --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error.R 2020-07-29 12:47:59.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("cnd-error") - test_that("error_cnd() checks its fields", { expect_no_error(error_cnd(trace = NULL)) expect_error(error_cnd(trace = env()), "`trace` must be NULL or an rlang backtrace") @@ -8,7 +6,6 @@ }) test_that("can use conditionMessage() method in subclasses of rlang errors", { - skip_unless_utf8() skip_if_stale_backtrace() run_error_script <- function(envvars = chr()) { @@ -20,11 +17,8 @@ non_interactive <- run_error_script() interactive <- run_error_script(envvars = "rlang_interactive=true") - verify_output(test_path("test-cnd-error-conditionMessage.txt"), { - "Interactive" + expect_snapshot({ cat_line(interactive) - - "Non-interactive" cat_line(non_interactive) }) }) @@ -44,12 +38,10 @@ # Handled error err <- catch_cnd(f()) - verify_output(test_path("test-error-print-conditionMessage.txt"), print(err)) + expect_snapshot(print(err)) }) test_that("error is printed with parent backtrace", { - skip_unless_utf8() - # Test low-level error can use conditionMessage() local_bindings(.env = global_env(), conditionMessage.foobar = function(c) c$foobar_msg @@ -84,19 +76,17 @@ `rlang:::error_pipe` = tempfile() ) - expect_known_output(file = test_path("test-cnd-error-parent-default.txt"), { + expect_snapshot({ print(err) print(err_force) }) - expect_known_output(file = test_path("test-cnd-error-parent-full.txt"), { + expect_snapshot({ print(err, simplify = "none") }) - expect_known_trace_output(err, file = "test-cnd-error-parent-trace.txt") + expect_snapshot_trace(err) }) test_that("summary.rlang_error() prints full backtrace", { - skip_unless_utf8() - local_options( rlang_trace_top_env = current_env(), rlang_trace_format_srcrefs = FALSE @@ -115,7 +105,7 @@ c <- function() tryCatch(f(), error = handler) err <- catch_cnd(a()) - expect_known_output(file = test_path("test-cnd-error-str.txt"), summary(err)) + expect_snapshot(summary(err)) }) test_that("can take the str() of an rlang error (#615)", { @@ -125,11 +115,11 @@ test_that("don't print message or backtrace fields if empty", { err <- error_cnd("foo", message = "") - expect_known_output(print(err), test_path("test-cnd-error-print-no-message.txt")) + expect_snapshot(print(err)) }) test_that("base parent errors are printed with rlang method", { base_err <- simpleError("foo") rlang_err <- error_cnd("bar", message = "", parent = base_err) - expect_known_output(print(rlang_err), test_path("test-cnd-error-print-base-parent.txt")) + expect_snapshot(print(rlang_err)) }) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-str.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-str.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error-str.txt 2020-10-07 08:39:55.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error-str.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -█ -├─ -│ The high-level error message -└─ - The low-level error message -Backtrace: - █ - 1. ├─rlang::catch_cnd(a()) - 2. │ ├─rlang::eval_bare(...) - 3. │ ├─base::tryCatch(...) - 4. │ │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 5. │ │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 6. │ │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 7. │ └─base::force(expr) - 8. └─rlang:::a() - 9. ├─base::tryCatch(b()) - 10. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 11. └─rlang:::b() - 12. └─rlang:::c() - 13. ├─base::tryCatch(f(), error = handler) - 14. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 15. │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 16. │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 17. └─rlang:::f() - 18. ├─base::tryCatch(g()) - 19. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 20. └─rlang:::g() - 21. └─rlang:::h() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-error.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-error.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-error.txt 2020-10-07 08:39:50.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-error.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -> # Default (interactive) -> cat_line(default_interactive) -Error: Error message -Run `rlang::last_error()` to see where the error occurred. -Execution halted - -> # Default (non-interactive) -> cat_line(default_non_interactive) -Error: Error message -Backtrace: - x - 1. \-global::f() - 2. +-base::tryCatch(g()) - 3. | \-base:::tryCatchList(expr, classes, parentenv, handlers) - 4. \-global::g() - 5. \-global::h() -Execution halted - -> # Reminder -> cat_line(reminder) -Error: Error message - -Execution halted - -> # Branch -> cat_line(branch) -Error: Error message -Backtrace: - 1. global::f() - 4. global::g() - 5. global::h() -Execution halted - -> # Collapse -> cat_line(collapse) -Error: Error message -Backtrace: - x - 1. \-global::f() - 2. +-[ base::tryCatch(...) ] with 1 more call - 4. \-global::g() - 5. \-global::h() -Execution halted - -> # Full -> cat_line(full) -Error: Error message -Backtrace: - x - 1. \-global::f() - 2. +-base::tryCatch(g()) - 3. | \-base:::tryCatchList(expr, classes, parentenv, handlers) - 4. \-global::g() - 5. \-global::h() -Execution halted - -> # Rethrown (interactive) -> cat_line(rethrown_interactive) -Error: Error message -Run `rlang::last_error()` to see where the error occurred. -Execution halted - -> # Rethrown (non-interactive) -> cat_line(rethrown_non_interactive) -Error: Error message -Backtrace: - x - 1. +-base::tryCatch(f(), error = function(cnd) rlang::cnd_signal(cnd)) - 2. | \-base:::tryCatchList(expr, classes, parentenv, handlers) - 3. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 4. | \-base:::doTryCatch(return(expr), name, parentenv, handler) - 5. \-global::f() - 6. +-base::tryCatch(g()) - 7. | \-base:::tryCatchList(expr, classes, parentenv, handlers) - 8. \-global::g() - 9. \-global::h() -Execution halted - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-handlers.R r-cran-rlang-0.4.10/tests/testthat/test-cnd-handlers.R --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-handlers.R 2020-07-08 17:48:30.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-handlers.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("cnd-handlers") - test_that("with_handlers() establishes inplace and exiting handlers", { handlers <- list( error = function(c) "caught error", @@ -32,7 +30,7 @@ expect_identical(with_handlers({ warning(""); "foo" }, warning = calling(cnd_muffle)), "foo") ) cnd_expect_muffle <- calling(function(cnd) { - expect_is(findRestart("rlang_muffle"), "restart") + expect_s3_class(findRestart("rlang_muffle"), "restart") cnd_muffle(cnd) }) expect_identical(with_handlers({ signal("", "cnd"); "foo" }, cnd = cnd_expect_muffle), "foo") @@ -40,15 +38,15 @@ test_that("can catch condition of specific classes", { expect_null(catch_cnd(signal("", "bar"), "foo")) - expect_is(catch_cnd(signal("", "bar"), "bar"), "bar") - expect_is(catch_cnd(stop(""), "error"), "error") + expect_s3_class(catch_cnd(signal("", "bar"), "bar"), "bar") + expect_s3_class(catch_cnd(stop(""), "error"), "error") - expect_is(catch_cnd(stop("tilt")), "error") + expect_s3_class(catch_cnd(stop("tilt")), "error") expect_error(catch_cnd(stop("tilt"), "foo"), "tilt") classes <- c("foo", "bar") - expect_is(catch_cnd(signal("", "bar"), classes), "bar") - expect_is(catch_cnd(signal("", "foo"), classes), "foo") + expect_s3_class(catch_cnd(signal("", "bar"), classes), "bar") + expect_s3_class(catch_cnd(signal("", "foo"), classes), "foo") }) test_that("with_handlers() registers calling handlers first (#718)", { @@ -81,3 +79,8 @@ )) expect_false(value) }) + +test_that("with_handlers() propagates visibility", { + expect_visible(with_handlers(list(invisible(1)))) + expect_invisible(with_handlers(invisible(1))) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-message.R r-cran-rlang-0.4.10/tests/testthat/test-cnd-message.R --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-message.R 2020-06-16 09:58:40.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-message.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("cnd-message") - test_that("format_error_bullets() formats bullets depending on names", { local_options( crayon.enabled = FALSE, diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd.R r-cran-rlang-0.4.10/tests/testthat/test-cnd.R --- r-cran-rlang-0.4.8/tests/testthat/test-cnd.R 2019-10-23 08:50:38.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,9 +1,7 @@ -context("cnd") - test_that("cnd() constructs all fields", { cond <- cnd("cnd_class", message = "cnd message") expect_identical(conditionMessage(cond), "cnd message") - expect_is(cond, "cnd_class") + expect_s3_class(cond, "cnd_class") }) test_that("cnd() throws with unnamed fields", { diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-signal.R r-cran-rlang-0.4.10/tests/testthat/test-cnd-signal.R --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-signal.R 2020-07-08 16:20:19.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-signal.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("cnd-signal") - test_that("cnd_signal() creates muffle restarts", { withCallingHandlers(cnd_signal(cnd("foo")), foo = function(c) { @@ -39,13 +37,13 @@ }) test_that("can signal and catch interrupts", { - expect_is(catch_cnd(interrupt()), "interrupt") + expect_s3_class(catch_cnd(interrupt()), "interrupt") }) test_that("can signal interrupts with cnd_signal()", { intr <- catch_cnd(interrupt()) with_handlers(cnd_signal(intr), - condition = function(cnd) expect_is(cnd, "interrupt") + condition = function(cnd) expect_s3_class(cnd, "interrupt") ) }) @@ -57,8 +55,6 @@ }) test_that("cnd_signal() creates a backtrace if needed", { - skip_unless_utf8() - local_options( rlang_trace_top_env = current_env(), rlang_trace_format_srcrefs = FALSE @@ -70,7 +66,7 @@ h <- function() cnd_signal(err) err <- catch_cnd(f()) - expect_known_output(file = test_path("test-cnd-signal-trace.txt"), print(err)) + expect_snapshot(print(err)) }) test_that("`inform()` appends newline to message", { @@ -179,6 +175,33 @@ expect_error(warn("foo", .frequency = "once"), "frequency_id") }) +test_that("cnd_signal() is a no-op with `NULL`", { + expect_null(catch_cnd(cnd_signal(NULL))) +}) + +test_that("`inform()` behaves consistently in interactive and non-interactive sessions (#1037)", { + # Default behaviour + out1 <- Rscript(shQuote(c("--vanilla", "-e", "rlang::inform('foo')"))) + out2 <- Rscript(shQuote(c("--vanilla", "-e", "rlang::with_interactive(rlang::inform('foo'))"))) + expect_equal(out1$out, "foo") + expect_equal(out1$out, out2$out) + + # Sinked behaviour + out1 <- Rscript(shQuote(c("--vanilla", "-e", "capture.output(rlang::inform('foo'))"))) + out2 <- Rscript(shQuote(c("--vanilla", "-e", "rlang::with_interactive(capture.output(rlang::inform('foo')))"))) + expect_equal(out1$out, c("foo", "character(0)")) + expect_equal(out1$out, out2$out) +}) + +test_that("`inform()` and `warn()` with recurrent footer handle newlines correctly", { + expect_snapshot({ + inform("foo", .frequency = "regularly", .frequency_id = as.character(runif(1))) + inform("bar", .frequency = "regularly", .frequency_id = as.character(runif(1))) + + warn("foo", .frequency = "regularly", .frequency_id = as.character(runif(1))) + warn("bar", .frequency = "regularly", .frequency_id = as.character(runif(1))) + }) +}) # Lifecycle ---------------------------------------------------------- @@ -193,3 +216,10 @@ foo = calling(function(cnd) expect_true(rst_exists("rlang_muffle"))) ) }) + +test_that("error_cnd() still accepts `.subclass`", { + expect_equal( + error_cnd(.subclass = "foo"), + error_cnd("foo") + ) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-cnd-signal-trace.txt r-cran-rlang-0.4.10/tests/testthat/test-cnd-signal-trace.txt --- r-cran-rlang-0.4.8/tests/testthat/test-cnd-signal-trace.txt 2020-10-07 08:39:56.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-cnd-signal-trace.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ - -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-compat.R r-cran-rlang-0.4.10/tests/testthat/test-compat.R --- r-cran-rlang-0.4.8/tests/testthat/test-compat.R 2018-12-17 14:37:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-compat.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("compat") - test_that("names() dispatches on environment", { env <- child_env(NULL, foo = "foo", bar = "bar") expect_identical(sort(names(env)), c("bar", "foo")) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-compat-zeallot.R r-cran-rlang-0.4.10/tests/testthat/test-compat-zeallot.R --- r-cran-rlang-0.4.8/tests/testthat/test-compat-zeallot.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-compat-zeallot.R 2020-11-24 11:21:07.000000000 +0000 @@ -0,0 +1,33 @@ + +test_that("LHS must be a list of symbols wrapped in `c()`", { + expect_error( + foo %<-% list(1), + "must be a call to `c()`", + fixed = TRUE + ) + + expect_error( + c(foo()) %<-% list(1), + "Element 1 of the left-hand side .* must be a symbol" + ) +}) + +test_that("can assign lists and vectors", { + c(foo, bar) %<-% list(a = 1, 2) + expect_equal(list(foo, bar), list(1, 2)) + + c(foo, bar) %<-% c(a = 1, 2) + expect_equal(list(foo, bar), list(1, 2)) +}) + +test_that("RHS and LHS must have the same length", { + expect_error( + c(foo) %<-% list(), + "must be the same length" + ) + + expect_error( + c(foo, bar) %<-% as.list(1:10), + "must be the same length" + ) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-deparse.R r-cran-rlang-0.4.10/tests/testthat/test-deparse.R --- r-cran-rlang-0.4.8/tests/testthat/test-deparse.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-deparse.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("deparse") - test_that("line_push() adds indentation", { out <- line_push("foo", "bar", width = 4, indent = 2) expect_identical(out, c("foo", " bar")) @@ -32,6 +30,7 @@ }) test_that("line_push() strips ANSI codes before computing overflow", { + local_options(crayon.enabled = TRUE) if (!has_crayon()) { skip("test needs crayon") } @@ -182,11 +181,15 @@ }) test_that("call_deparse() delimits CAR when needed", { - call <- expr((!!quote(function() x + 1))()) + fn_call <- quote(function() x + 1) + call <- expr((!!fn_call)()) expect_identical(call_deparse(call), "(function() x + 1)()") - # Only equal because of the extra parentheses - expect_equal(parse_expr(expr_deparse(call)), call) + roundtrip <- parse_expr(expr_deparse(call)) + exp <- call2(call("(", fn_call)) + + # Zap srcref to work around https://github.com/r-lib/waldo/issues/59 + expect_equal(zap_srcref(roundtrip), zap_srcref(exp)) call <- expr((!!quote(f + g))(x)) expect_identical(call_deparse(call), "`+`(f, g)(x)") @@ -407,7 +410,6 @@ }) test_that("symbols with unicode are deparsed consistently (#691)", { - skip_unless_utf8() skip_if(getRversion() < "3.2") expect_identical(expr_text(sym("\u00e2a")), "\u00e2a") @@ -477,3 +479,44 @@ test_that("argument names are backticked if needed (#950)", { expect_identical(expr_deparse(quote(list(`a b` = 1))), "list(`a b` = 1)") }) + +test_that("`next` and `break` are deparsed", { + expect_equal(expr_deparse(quote({ next; (break) })), c("{", " next", " (break)", "}")) + expect_equal(expr_deparse(quote(a <- next <- break)), c("a <- next <- break")) +}) + +test_that("double colon is never wrapped (#1072)", { + expect_identical( + expr_deparse(quote(some.very.long::construct), width = 20), + "some.very.long::construct" + ) + expect_identical( + expr_deparse(quote(id_function <- base::identity), width = 15), + c( + "id_function <-", + " base::identity" + ) + ) + expect_identical( + expr_deparse(quote(id_fun <- base::identity), width = 20), + "id_fun <- base::identity" + ) +}) + +test_that("triple colon is never wrapped (#1072)", { + expect_identical( + expr_deparse(quote(some.very.long:::construct), width = 20), + "some.very.long:::construct" + ) + expect_identical( + expr_deparse(quote(id_function <- base:::identity), width = 15), + c( + "id_function <-", + " base:::identity" + ) + ) + expect_identical( + expr_deparse(quote(id_fun <- base:::identity), width = 20), + "id_fun <- base:::identity" + ) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-dots.R r-cran-rlang-0.4.10/tests/testthat/test-dots.R --- r-cran-rlang-0.4.8/tests/testthat/test-dots.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-dots.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("dots") - test_that("exprs() without arguments creates an empty named list", { expect_identical(exprs(), named_list()) }) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-encoding.R r-cran-rlang-0.4.10/tests/testthat/test-encoding.R --- r-cran-rlang-0.4.8/tests/testthat/test-encoding.R 2019-06-13 11:36:26.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-encoding.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("encoding") - test_that("can roundtrip symbols in non-UTF8 locale", { with_non_utf8_locale({ expect_identical( diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-entrace.txt r-cran-rlang-0.4.10/tests/testthat/test-entrace.txt --- r-cran-rlang-0.4.8/tests/testthat/test-entrace.txt 2020-10-07 08:39:54.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-entrace.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ - -base error -========== - -> cat_line(base) -Error in h() : foo -Calls: f -> g -> h -Run `rlang::last_error()` to see where the error occurred. - -foo -Backtrace: - 1. global::f() - 2. global::g() - 3. global::h() -Run `rlang::last_trace()` to see the full context. - -foo -Backtrace: - █ - 1. └─global::f() - 2. └─global::g() - 3. └─global::h() - - -rlang error -=========== - -> cat_line(rlang) -Error: foo -Run `rlang::last_error()` to see where the error occurred. - -foo -Backtrace: - 1. global::f() - 2. global::g() - 3. global::h() -Run `rlang::last_trace()` to see the full context. - -foo -Backtrace: - █ - 1. └─global::f() - 2. └─global::g() - 3. └─global::h() - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-env-binding.R r-cran-rlang-0.4.10/tests/testthat/test-env-binding.R --- r-cran-rlang-0.4.8/tests/testthat/test-env-binding.R 2020-06-26 13:10:13.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-env-binding.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("env-binding") - test_that("promises are created", { env <- child_env(NULL) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-env.R r-cran-rlang-0.4.10/tests/testthat/test-env.R --- r-cran-rlang-0.4.8/tests/testthat/test-env.R 2020-07-29 17:59:56.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-env.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("env") - test_that("env_parent() returns enclosure frame by default", { enclos_env <- child_env(pkg_env("rlang")) fn <- with_env(enclos_env, function() env_parent()) @@ -419,11 +417,11 @@ out <- envs[1:2] expect_length(out, 2) - expect_is(out, "rlang_envs") + expect_s3_class(out, "rlang_envs") out <- envs[3] expect_length(out, 1) - expect_is(out, "rlang_envs") + expect_s3_class(out, "rlang_envs") }) test_that("can concatenate `rlang_envs` lists", { @@ -431,7 +429,7 @@ envs2 <- new_environments(list(env(), env())) out <- c(envs1, envs2) expect_length(out, 3) - expect_is(out, "rlang_envs") + expect_s3_class(out, "rlang_envs") }) test_that("env_name() requires an environment", { @@ -457,6 +455,19 @@ expect_identical(get_env(is.null), ns_env("base")) }) +test_that("can browse environments", { + env <- env() + expect_false(env_is_browsed(env)) + + old <- env_browse(env) + expect_false(old) + expect_true(env_is_browsed(env)) + + old <- env_browse(env, FALSE) + expect_true(old) + expect_false(env_is_browsed(env)) +}) + # Lifecycle --------------------------------------------------------- diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-env-special.R r-cran-rlang-0.4.10/tests/testthat/test-env-special.R --- r-cran-rlang-0.4.8/tests/testthat/test-env-special.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-env-special.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("env-special") - test_that("search_envs() includes the global and base env", { envs <- search_envs() expect_identical(envs[[1]], global_env()) @@ -11,7 +9,7 @@ }) test_that("search_envs() returns an rlang_envs object", { - expect_is(search_envs(), "rlang_envs") + expect_s3_class(search_envs(), "rlang_envs") }) test_that("is_namespace() recognises namespaces", { @@ -86,3 +84,13 @@ test_that("is_installed() properly checks multiple packages", { expect_false(is_installed(c("base", "no.notarealpackagename"))) }) + +test_that("check_installed() fails if packages are not installed", { + local_options(rlang_interactive = FALSE) + + expect_snapshot({ + (expect_error(check_installed("_foo"))) + (expect_error(check_installed(c("_foo", "_bar")))) + (expect_error(check_installed(c("_foo", "_bar"), "to proceed."))) + }) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-error-print-conditionMessage.txt r-cran-rlang-0.4.10/tests/testthat/test-error-print-conditionMessage.txt --- r-cran-rlang-0.4.8/tests/testthat/test-error-print-conditionMessage.txt 2020-10-07 08:39:55.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-error-print-conditionMessage.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -> print(err) - -Low-level message -Backtrace: - 1. rlang::catch_cnd(f()) - 8. rlang:::f() - 9. rlang:::g() - 10. rlang:::h() - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-eval.R r-cran-rlang-0.4.10/tests/testthat/test-eval.R --- r-cran-rlang-0.4.8/tests/testthat/test-eval.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-eval.R 2020-11-19 16:07:27.000000000 +0000 @@ -0,0 +1,31 @@ + +test_that("supports tidy dots", { + expect_equal(exec(list, x = 1), list(x = 1)) + + args <- list(x = 1) + expect_equal(exec(list, !!!args), list(x = 1)) + expect_equal(exec(list, !!!args, y = 2), list(x = 1, y = 2)) +}) + +test_that("does not inline expressions", { + expect_equal(exec(list, x = expr(x), y = expr(y)), exprs(x = x, y = y)) +}) + +test_that("inject() injects", { + expect_equal_( + inject(quote(foo(!!(1:2), !!!1:3))), + call2("foo", 1:2, !!!1:3) + ) + + g <- function(x) substitute(x) + f <- function(x) inject(g({{ x }})) + expect_equal( + f(foo()), + quo(foo()) + ) +}) + +test_that("inject() and eval_bare() propagate visibility", { + expect_invisible(eval_bare(quote(invisible(list())))) + expect_invisible(inject(invisible(list()))) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-eval-tidy.R r-cran-rlang-0.4.10/tests/testthat/test-eval-tidy.R --- r-cran-rlang-0.4.8/tests/testthat/test-eval-tidy.R 2020-07-09 09:16:35.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-eval-tidy.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("eval-tidy") - test_that("accepts expressions", { expect_identical(eval_tidy(10), 10) expect_identical(eval_tidy(quote(letters)), letters) @@ -128,8 +126,16 @@ var <- quo(cyl) expect_identical(fn(mtcars, (!!var) > 4), mtcars$cyl > 4) expect_identical(fn(mtcars, list(var, !!var)), list(quo(cyl), mtcars$cyl)) - expect_equal(fn(mtcars, list(~var, !!var)), list(~var, mtcars$cyl)) - expect_equal(fn(mtcars, list(~~var, !!quo(var), !!quo(quo(var)))), list(~~var, quo(cyl), quo(var))) + expect_equal( + fn(mtcars, list(~var, !!var)), + list(~var, mtcars$cyl), + ignore_formula_env = TRUE + ) + expect_equal( + fn(mtcars, list(~~var, !!quo(var), !!quo(quo(var)))), + list(~~var, quo(cyl), quo(var)), + ignore_formula_env = TRUE + ) }) test_that("can unquote for old-style NSE functions", { @@ -194,7 +200,7 @@ ~foo }) f <- eval_tidy(quo) - expect_true(env_has(f, "foo")) + expect_true(env_has(f_env(f), "foo")) }) test_that(".env pronoun refers to current quosure (#174)", { @@ -212,8 +218,16 @@ }) test_that("can call tilde with named arguments (#226)", { - expect_equal(eval_tidy(quote(`~`(foo = x, bar = y))), x ~ y) - expect_equal(eval_tidy(quote(`~`(foo = x, bar = y, baz = z))), `~`(foo = x, bar = y, baz = z)) + expect_equal( + eval_tidy(quote(`~`(foo = x, bar = y))), + `~`(foo = x, bar = y), + ignore_formula_env = TRUE + ) + expect_equal( + eval_tidy(quote(`~`(foo = x, bar = y, baz = z))), + `~`(foo = x, bar = y, baz = z), + ignore_formula_env = TRUE + ) }) test_that("Arguments to formulas are not stripped from their attributes (#227)", { @@ -238,7 +252,7 @@ test_that("as_data_pronoun() creates pronoun", { data <- as_data_pronoun(mtcars) - expect_is(data, "rlang_data_pronoun") + expect_s3_class(data, "rlang_data_pronoun") data_env <- .subset2(data, 1) expect_reference(env_parent(data_env), empty_env()) @@ -254,7 +268,7 @@ mask <- new_data_mask(bottom, top) .data <- as_data_pronoun(mask) - expect_is(.data, "rlang_data_pronoun") + expect_s3_class(.data, "rlang_data_pronoun") expect_identical(.data$a, 1) expect_identical(.data$b, 2) }) @@ -376,13 +390,13 @@ expect_output(print(rlang::.data), "") }) -test_that("data pronoun always skips functions", { +test_that("data pronoun doesn't skip functions (#1061, #5608)", { top <- env(c = "c") bottom <- env(top, c = base::c) mask <- new_data_mask(bottom, top) .data <- as_data_pronoun(mask) - expect_identical(.data$c, "c") + expect_identical(.data$c, base::c) }) test_that("leaked quosure masks are not mistaken with data masks", { @@ -409,7 +423,7 @@ test_that("`.env` pronoun is constructed", { pronoun <- eval_tidy(quote(.env), mtcars) - expect_is(pronoun, "rlang_ctxt_pronoun") + expect_s3_class(pronoun, "rlang_ctxt_pronoun") expect_reference(env_parent(pronoun), current_env()) }) @@ -469,6 +483,12 @@ ) }) +test_that("eval_tidy() propagates visibility", { + expect_visible(eval_tidy(quo(list(invisible(list()))))) + expect_invisible(eval_tidy(quo(invisible(list())))) + expect_invisible(eval_tidy(quo(identity(!!local(quo(invisible(list()))))))) +}) + # Lifecycle ---------------------------------------------------------- diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-exec.R r-cran-rlang-0.4.10/tests/testthat/test-exec.R --- r-cran-rlang-0.4.8/tests/testthat/test-exec.R 2018-12-17 14:37:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-exec.R 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -context("test-exec") - -test_that("supports tidy dots", { - expect_equal(exec(list, x = 1), list(x = 1)) - - args <- list(x = 1) - expect_equal(exec(list, !!!args), list(x = 1)) - expect_equal(exec(list, !!!args, y = 2), list(x = 1, y = 2)) -}) - -test_that("does not inline expressions", { - expect_equal(exec(list, x = expr(x), y = expr(y)), exprs(x = x, y = y)) -}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-expr.R r-cran-rlang-0.4.10/tests/testthat/test-expr.R --- r-cran-rlang-0.4.8/tests/testthat/test-expr.R 2019-10-23 08:50:38.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-expr.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("expr") - # expr_text() -------------------------------------------------------- test_that("always returns single string", { diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-fn.R r-cran-rlang-0.4.10/tests/testthat/test-fn.R --- r-cran-rlang-0.4.8/tests/testthat/test-fn.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-fn.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("function") - test_that("new_function equivalent to regular function", { f1 <- function(x = a + b, y) { x + y @@ -251,7 +249,7 @@ test_that("as_function() adds a class to lambda functions", { out <- as_function(~foo) - expect_is(out, c("rlang_lambda_function", "function")) + expect_s3_class(out, c("rlang_lambda_function", "function")) expect_output(print(out), "") }) @@ -289,3 +287,32 @@ test_that("transforming defused formula to function causes an informative error (#953)", { expect_error(as_function(quote(~foo)), "defused formula") }) + +test_that("functions created from quosures with as_function() print properly", { + fn <- as_function(quo(x)) + expect_equal(body(fn), quote(x)) +}) + +test_that("as_function() creates functions that respect visibility", { + f <- as_function(quo(invisible(1))) + expect_invisible(f()) + + f <- as_function(quo(1)) + expect_visible(f()) + + f <- as_function(~ invisible(1)) + expect_invisible(f()) + + f <- as_function(~ 1) + expect_visible(f()) +}) + +test_that("as_function() with a quosure can be serialised", { + fn <- as_function(local({ a <- 10; quo(a) })) + blob <- serialize(fn, NULL) + expect_equal( + eval_tidy(fn), + eval_tidy(unserialize(blob)), + ignore_function_env = TRUE + ) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-formula.R r-cran-rlang-0.4.10/tests/testthat/test-formula.R --- r-cran-rlang-0.4.8/tests/testthat/test-formula.R 2018-12-17 14:37:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-formula.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("formula") - # Creation ---------------------------------------------------------------- test_that("is_formula works", { diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-hash.R r-cran-rlang-0.4.10/tests/testthat/test-hash.R --- r-cran-rlang-0.4.8/tests/testthat/test-hash.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-hash.R 2020-12-18 09:31:10.000000000 +0000 @@ -0,0 +1,5 @@ +test_that("simple hashes with no ALTREP and no attributes are reproducible", { + expect_identical(hash(1), "a3f7d4a39b65b170005aafbbeed05106") + expect_identical(hash("a"), "4d52a7da68952b85f039e85a90f9bbd2") + expect_identical(hash(1:5 + 0L), "0d26bf75943b8e13c080c6bab12a7440") +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-lifecycle.R r-cran-rlang-0.4.10/tests/testthat/test-lifecycle.R --- r-cran-rlang-0.4.8/tests/testthat/test-lifecycle.R 2020-02-26 17:16:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-lifecycle.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("lifecycle") - test_that("signal_soft_deprecated() warns when called from global env", { old <- Sys.getenv("TESTTHAT_PKG") Sys.setenv("TESTTHAT_PKG" = "") diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-node.R r-cran-rlang-0.4.10/tests/testthat/test-node.R --- r-cran-rlang-0.4.8/tests/testthat/test-node.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-node.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,8 +1,6 @@ -context("node") - test_that("node() creates a pairlist node", { x <- new_node("foo", "bar") - expect_is(x, "pairlist") + expect_type(x, "pairlist") expect_identical(node_car(x), "foo") expect_identical(node_cdr(x), "bar") }) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-nse-defuse.R r-cran-rlang-0.4.10/tests/testthat/test-nse-defuse.R --- r-cran-rlang-0.4.8/tests/testthat/test-nse-defuse.R 2020-06-26 16:40:11.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-nse-defuse.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("nse-defuse") - test_that("quos() creates quosures", { fs <- quos(x = 1 + 2, y = 2 + 3) expect_identical(fs$x, as_quosure(~ 1 + 2)) @@ -435,7 +433,11 @@ }) test_that("the missing argument is captured", { - expect_equal_(quos(!!missing_arg()), quos(, )) + expect_equal_( + quos(!!missing_arg()), + quos(, ), + ignore_formula_env = TRUE + ) fn <- function(x) { g(!!enquo(x)) @@ -443,7 +445,11 @@ g <- function(...) { quos(...) } - expect_equal_(fn(), quos(!!missing_arg())) + expect_equal_( + fn(), + quos(!!missing_arg()), + ignore_formula_env = TRUE + ) }) test_that("missing names are forwarded", { @@ -509,3 +515,27 @@ expect_identical(fn(!!!quos(foo, "bar")), exprs(foo, bar)) expect_error(fn(!!!quos(foo, bar())), "Only strings can be converted to symbols") }) + +test_that("enquo0() and enquos0() capture arguments without injection", { + fn <- function(arg) enquo0(arg) + expect_equal( + fn(foo(!!1)), + quo(foo(!!quote(!!1))) + ) + + fn <- function(...) enquos0(...) + expect_equal_( + fn(x = foo(!!1), !!!1:3, z = 3), + list(x = quo(foo(!!quote(!!1))), quo(!!quote(!!!1:3)), z = quo(3)) + ) +}) + +test_that("enquo0() and enquos0() don't rewrap quosures", { + fn <- function(arg) enquo0(arg) + quo <- local(quo(x)) + expect_equal(fn(!!quo), quo) + + fn <- function(...) enquos0(...) + quo <- local(quo(x)) + expect_equal(fn(!!quo), list(quo)) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-nse-force.R r-cran-rlang-0.4.10/tests/testthat/test-nse-force.R --- r-cran-rlang-0.4.8/tests/testthat/test-nse-force.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-nse-force.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("nse-force") - test_that("interpolation does not recurse over spliced arguments", { var2 <- quote({foo; !! stop(); bar}) expr_var2 <- tryCatch(expr(list(!!! var2)), error = identity) @@ -62,7 +60,7 @@ test_that("unquoted quosure has S3 class", { quo <- quo(!! ~quo) - expect_is(quo, "quosure") + expect_s3_class(quo, "quosure") }) test_that("unquoted quosures are not guarded", { @@ -170,10 +168,10 @@ local_lifecycle_silence() quo <- quo(UQ(NULL)) - expect_equal(quo, ~NULL) + expect_equal(quo, quo(NULL)) quo <- tryCatch(quo(UQ()), error = identity) - expect_is(quo, "error") + expect_s3_class(quo, "error") expect_match(quo$message, "must be called with an argument") }) @@ -642,10 +640,10 @@ expect_identical(quo(list(rlang::UQS(list(a = 1, b = 2)))), quo(list(a = 1, b = 2))) quo <- quo(rlang::UQ(NULL)) - expect_equal(quo, ~NULL) + expect_equal(quo, quo(NULL)) quo <- tryCatch(quo(rlang::UQ()), error = identity) - expect_is(quo, "error") + expect_s3_class(quo, "error") expect_match(quo$message, "must be called with an argument") expect_error_(dots_values(rlang::UQ(quote(.))), "`!!` in a non-quoting function") @@ -722,3 +720,9 @@ expect_identical(expr(call(.data[[quo(foo)]])), quote(call(.data[["foo"]]))) expect_identical(expr(call(.data[[!!quo(foo)]])), quote(call(.data[["foo"]]))) }) + +test_that("can splice named empty vectors (#1045)", { + # Work around bug in `Rf_coerceVector()` + x <- named(dbl()) + expect_equal(expr(foo(!!!x)), quote(foo())) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-operators.R r-cran-rlang-0.4.10/tests/testthat/test-operators.R --- r-cran-rlang-0.4.8/tests/testthat/test-operators.R 2020-02-27 18:24:24.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-operators.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("operators") - test_that("%|% returns default value", { lgl <- c(TRUE, TRUE, NA, FALSE) %|% FALSE expect_identical(lgl, c(TRUE, TRUE, FALSE, FALSE)) @@ -34,42 +32,20 @@ expect_equal(cpx, c(1i, 2i, 12i, 4i)) }) -test_that("%|% fails on non-atomic original values", { - verify_errors({ - expect_error(call("fn") %|% 1) - }) -}) - test_that("%|% fails with wrong types", { - verify_errors({ - expect_error(c(1L, NA) %|% 2) - expect_error(c(1, NA) %|% "") - expect_error(c(1, NA) %|% call("fn")) + expect_snapshot({ + (expect_error(c(1L, NA) %|% 2)) + (expect_error(c(1, NA) %|% "")) + (expect_error(c(1, NA) %|% call("fn"))) + (expect_error(call("fn") %|% 1)) }) }) test_that("%|% fails with wrong length", { - verify_errors({ - expect_error(c(1L, NA) %|% 1:3) - expect_error(1:10 %|% 1:4) - expect_error(1L %|% 1:4) - }) -}) - -test_that("%|% fails with intelligent errors", { - verify_output(test_path("test-operators-replace-na.txt"), { - "# %|% fails on non-atomic original values" - call("fn") %|% 1 - - "# %|% fails with wrong types" - c(1L, NA) %|% 2 - c(1, NA) %|% "" - c(1, NA) %|% call("fn") - - "# %|% fails with wrong length" - c(1L, NA) %|% 1:3 - 1:10 %|% 1:4 - 1L %|% 1:4 + expect_snapshot({ + (expect_error(c(1L, NA) %|% 1:3)) + (expect_error(1:10 %|% 1:4)) + (expect_error(1L %|% 1:4)) }) }) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-operators-replace-na.txt r-cran-rlang-0.4.10/tests/testthat/test-operators-replace-na.txt --- r-cran-rlang-0.4.8/tests/testthat/test-operators-replace-na.txt 2020-10-07 08:40:11.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-operators-replace-na.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ - -%|% fails on non-atomic original values -======================================= - -> call("fn") %|% 1 -Error: Cannot replace missing values in an object of type language - - -%|% fails with wrong types -========================== - -> c(1L, NA) %|% 2 -Error: Replacement values must have type integer, not type double - -> c(1, NA) %|% "" -Error: Replacement values must have type double, not type character - -> c(1, NA) %|% call("fn") -Error: Replacement values must have type double, not type language - - -%|% fails with wrong length -=========================== - -> c(1L, NA) %|% 1:3 -Error: The replacement values must have size 1 or 2, not 3 - -> 1:10 %|% 1:4 -Error: The replacement values must have size 1 or 10, not 4 - -> 1L %|% 1:4 -Error: The replacement values must have size 1, not 4 - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-parse.R r-cran-rlang-0.4.10/tests/testthat/test-parse.R --- r-cran-rlang-0.4.8/tests/testthat/test-parse.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-parse.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("parse") - test_that("parse_quo() etc return quosures", { expect_identical(parse_quo("foo(bar)", "base"), set_env(quo(foo(bar)), base_env())) expect_identical(parse_quos("foo(bar)\n mtcars", "base"), new_quosures(list(set_env(quo(foo(bar)), base_env()), set_env(quo(mtcars), base_env())))) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-quo.R r-cran-rlang-0.4.10/tests/testthat/test-quo.R --- r-cran-rlang-0.4.8/tests/testthat/test-quo.R 2020-02-26 14:19:21.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-quo.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("quo") - test_that("quo_get_expr() and quo_get_env() retrieve quosure components", { quo <- quo(foo) expect_identical(quo_get_expr(quo), quote(foo)) @@ -82,14 +80,6 @@ expect_identical(out_quo$quo, quo) }) -test_that("explicit promise makes a formula", { - capture <- function(x) enquo(x) - f1 <- capture(1 + 2 + 3) - f2 <- ~ 1 + 2 + 3 - - expect_equal(f1, f2) -}) - test_that("explicit promise works only one level deep", { f <- function(x) list(env = current_env(), f = g(x)) g <- function(y) enquo(y) @@ -147,7 +137,7 @@ }) test_that("quo_squash() warns", { - expect_warning(regex = NA, quo_squash(quo(foo), warn = TRUE)) + expect_warning(regexp = NA, quo_squash(quo(foo), warn = TRUE)) expect_warning(quo_squash(quo(list(!! quo(foo))), warn = TRUE), "inner quosure") }) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-retired.R r-cran-rlang-0.4.10/tests/testthat/test-retired.R --- r-cran-rlang-0.4.8/tests/testthat/test-retired.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-retired.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("retired") - local_lifecycle_silence() @@ -17,12 +15,12 @@ expect_identical(type_of(quote(foo())), "language") }) -test_that("Unicode escapes are always converted to UTF8 characters in as_list()", { +test_that("Unicode escapes are converted to UTF8 characters in env_names()", { with_non_utf8_locale({ env <- child_env(empty_env()) - env_bind(env, !! get_alien_lang_string() := NULL) - list <- as_list(env) - expect_identical(names(list), get_alien_lang_string()) + env_bind(env, !!get_alien_lang_string() := NULL) + nms <- env_names(env) + expect_identical(nms, get_alien_lang_string()) }) }) @@ -54,7 +52,7 @@ x <- structure(child_env(NULL), class = "foo") y <- as_list(x) - expect_is(x, "foo") + expect_s3_class(x, "foo") expect_identical(y, set_names(list(), character(0))) }) @@ -170,7 +168,7 @@ test_that("as_env() forwards to as_environment()", { x <- as_env(mtcars, base_env()) y <- as_environment(mtcars, base_env()) - expect_equal(x, y) + expect_equal(as.list(x), as.list(y)) expect_identical(env_parent(x), env_parent(y)) }) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-s3.R r-cran-rlang-0.4.10/tests/testthat/test-s3.R --- r-cran-rlang-0.4.8/tests/testthat/test-s3.R 2019-04-23 12:33:50.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-s3.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("s3") - test_that("inherits from all classes", { x <- structure(list(), class = c("foo", "bar", "baz")) @@ -77,7 +75,7 @@ }) test_that("zap() creates a zap", { - expect_is(zap(), "rlang_zap") + expect_s3_class(zap(), "rlang_zap") expect_true(is_zap(zap())) }) @@ -98,7 +96,7 @@ expect_identical(unbox(empty), missing_arg()) expect_true(is_done_box(empty)) - expect_is(empty, "rlang_box_done") + expect_s3_class(empty, "rlang_box_done") expect_identical(empty %@% empty, TRUE) expect_true(is_done_box(empty, empty = TRUE)) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-sexp.R r-cran-rlang-0.4.10/tests/testthat/test-sexp.R --- r-cran-rlang-0.4.8/tests/testthat/test-sexp.R 2018-12-17 14:37:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-sexp.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("sexp") - test_that("poke_type() changes object type", { x <- new_node(quote(foo), NULL) out <- withVisible(poke_type(x, "language")) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-stack.R r-cran-rlang-0.4.10/tests/testthat/test-stack.R --- r-cran-rlang-0.4.8/tests/testthat/test-stack.R 2018-12-17 14:37:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-stack.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("stack") - test_that("can return from frame", { fn <- function() { val <- g() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-state.R r-cran-rlang-0.4.10/tests/testthat/test-state.R --- r-cran-rlang-0.4.8/tests/testthat/test-state.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-state.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("state") - test_that("options are set temporarily", { local_options(foo = "foo") expect_identical(with_options(foo = "bar", peek_option("foo")), "bar") diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-sym.R r-cran-rlang-0.4.10/tests/testthat/test-sym.R --- r-cran-rlang-0.4.8/tests/testthat/test-sym.R 2019-01-03 19:55:19.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-sym.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("sym") - test_that("ensym() fails with calls", { capture_sym <- function(arg) ensym(arg) expect_identical(capture_sym(foo), quote(foo)) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-backtrace-anonymous.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-backtrace-anonymous.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-backtrace-anonymous.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-backtrace-anonymous.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -Full: - █ - 1. └─(function() {... - -Collapsed: - █ - 1. └─(function() {... - -Branch: - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-backtrace-branch-first-frame.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-backtrace-branch-first-frame.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-backtrace-branch-first-frame.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-backtrace-branch-first-frame.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. ├─rlang:::gen() - 2. └─rlang:::gen.default() - -Collapsed: - █ - 1. ├─[ rlang:::gen() ] - 2. └─rlang:::gen.default() - -Branch: - 1. rlang:::gen() - 2. rlang:::gen.default() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-call-car-promise.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-call-car-promise.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-call-car-promise.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-call-car-promise.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. ├─base::print(foo) - 2. └─rlang:::print.foo(foo) - -Collapsed: - █ - 1. ├─[ base::print(...) ] - 2. └─rlang:::print.foo(foo) - -Branch: - 1. base::print(foo) - 2. rlang:::print.foo(foo) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-children.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-children.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-children.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-children.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -Full: - █ - 1. └─rlang:::f() - 2. └─base::eval(quote(g()), env()) - 3. └─base::eval(quote(g()), env()) - 4. └─rlang:::g() - -Collapsed: - █ - 1. └─rlang:::f() - 2. └─[ base::eval(...) ] with 1 more call - 4. └─rlang:::g() - -Branch: - 1. rlang:::f() - 2. [ base::eval(...) ] with 1 more call - 4. rlang:::g() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapsed1.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapsed1.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapsed1.txt 2020-10-07 08:46:26.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapsed1.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -Full: - █ - 1. └─rlang:::f() - 2. └─rlang:::g() test-trace.R:57:20 - 3. ├─base::tryCatch(h(), foo = identity, bar = identity) test-trace.R:58:20 - 4. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 5. │ ├─base:::tryCatchOne(...) - 6. │ │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 7. │ └─base:::tryCatchList(expr, names[-nh], parentenv, handlers[-nh]) - 8. │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 9. │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 10. └─rlang:::h() - 11. ├─base::tryCatch(i(), baz = identity) test-trace.R:59:20 - 12. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 13. │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 14. │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 15. └─rlang:::i() - 16. ├─base::tryCatch(trace_back(e, bottom = 0)) test-trace.R:60:20 - 17. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 18. └─rlang::trace_back(e, bottom = 0) - -Collapsed: - █ - 1. └─rlang:::f() - 2. └─rlang:::g() test-trace.R:57:20 - 3. ├─[ base::tryCatch(...) ] with 6 more calls test-trace.R:58:20 - 10. └─rlang:::h() - 11. ├─[ base::tryCatch(...) ] with 3 more calls test-trace.R:59:20 - 15. └─rlang:::i() - 16. ├─[ base::tryCatch(...) ] with 1 more call test-trace.R:60:20 - 18. └─rlang::trace_back(e, bottom = 0) - -Branch: - 1. rlang:::f() - 2. rlang:::g() test-trace.R:57:20 - 10. rlang:::h() - 15. rlang:::i() - 18. rlang::trace_back(e, bottom = 0) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapsed2.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapsed2.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapsed2.txt 2020-10-07 08:46:26.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapsed2.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -Full: - █ - 1. └─rlang:::f() - 2. ├─base::eval(quote(eval(quote(g())))) test-trace.R:70:7 - 3. │ └─base::eval(quote(eval(quote(g())))) - 4. ├─base::eval(quote(g())) - 5. │ └─base::eval(quote(g())) - 6. └─rlang:::g() - 7. ├─base::tryCatch(eval(quote(h())), foo = identity, bar = identity) test-trace.R:71:7 - 8. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 9. │ ├─base:::tryCatchOne(...) - 10. │ │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 11. │ └─base:::tryCatchList(expr, names[-nh], parentenv, handlers[-nh]) - 12. │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 13. │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 14. ├─base::eval(quote(h())) - 15. │ └─base::eval(quote(h())) - 16. └─rlang:::h() - -Collapsed: - █ - 1. └─rlang:::f() - 2. ├─[ base::eval(...) ] with 1 more call test-trace.R:70:7 - 4. ├─[ base::eval(...) ] with 1 more call - 6. └─rlang:::g() - 7. ├─[ base::tryCatch(...) ] with 6 more calls test-trace.R:71:7 - 14. ├─[ base::eval(...) ] with 1 more call - 16. └─rlang:::h() - -Branch: - 1. rlang:::f() - 6. rlang:::g() - 16. rlang:::h() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-evalq.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-evalq.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-evalq.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-evalq.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Full: - █ - 1. └─rlang:::f() - 2. ├─base::evalq(g()) - 3. │ └─base::evalq(g()) - 4. └─rlang:::g() - 5. ├─base::evalq(trace_back(e, bottom = 0)) - 6. │ └─base::evalq(trace_back(e, bottom = 0)) - 7. └─rlang::trace_back(e, bottom = 0) - -Collapsed: - █ - 1. └─rlang:::f() - 2. ├─[ base::evalq(...) ] with 1 more call - 4. └─rlang:::g() - 5. ├─[ base::evalq(...) ] with 1 more call - 7. └─rlang::trace_back(e, bottom = 0) - -Branch: - 1. rlang:::f() - 4. rlang:::g() - 7. rlang::trace_back(e, bottom = 0) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-eval.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-eval.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-eval.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-eval.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Full: - █ - 1. └─rlang:::f() - 2. ├─base::eval(quote(g())) - 3. │ └─base::eval(quote(g())) - 4. └─rlang:::g() - 5. ├─base::eval(quote(trace_back(e, bottom = 0))) - 6. │ └─base::eval(quote(trace_back(e, bottom = 0))) - 7. └─rlang::trace_back(e, bottom = 0) - -Collapsed: - █ - 1. └─rlang:::f() - 2. ├─[ base::eval(...) ] with 1 more call - 4. └─rlang:::g() - 5. ├─[ base::eval(...) ] with 1 more call - 7. └─rlang::trace_back(e, bottom = 0) - -Branch: - 1. rlang:::f() - 4. rlang:::g() - 7. rlang::trace_back(e, bottom = 0) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr2.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr2.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr2.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr2.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. ├─f(NULL) %>% g(list(.)) %>% h(3, ., list(.)) - 2. └─rlang:::h(3, ., list(.)) - -Collapsed: - █ - 1. ├─[ f(NULL) %>% g(list(.)) %>% h(3, ., list(.)) ] - 2. └─rlang:::h(3, ., list(.)) - -Branch: - 1. f(NULL) %>% g(list(.)) %>% h(3, ., list(.)) - 2. rlang:::h(3, ., list(.)) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr3.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr3.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr3.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr3.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -Full: - █ - 1. ├─rlang:::f(g(NULL %>% f()) %>% h()) - 2. ├─g(NULL %>% f()) %>% h() - 3. └─rlang:::h(.) - -Collapsed: - █ - 1. ├─[ rlang:::f(...) ] - 2. ├─[ g(NULL %>% f()) %>% h() ] - 3. └─rlang:::h(.) - -Branch: - 1. rlang:::f(g(NULL %>% f()) %>% h()) - 3. rlang:::h(.) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-before-after1.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-before-after1.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-before-after1.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-before-after1.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -Full: - █ - 1. ├─rlang:::F(NA %>% T()) - 2. ├─NA %>% T() - 3. └─rlang:::T(.) - -Collapsed: - █ - 1. ├─[ rlang:::F(...) ] - 2. ├─[ NA %>% T() ] - 3. └─rlang:::T(.) - -Branch: - 1. rlang:::F(NA %>% T()) - 3. rlang:::T(.) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-before-after2.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-before-after2.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-before-after2.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-before-after2.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -Full: - █ - 1. ├─NA %>% C() - 2. └─rlang:::C(.) - 3. └─rlang:::f() - -Collapsed: - █ - 1. ├─[ NA %>% C() ] - 2. └─rlang:::C(.) - 3. └─rlang:::f() - -Branch: - 1. NA %>% C() - 2. rlang:::C(.) - 3. rlang:::f() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-before-after3.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-before-after3.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-before-after3.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-before-after3.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -Full: - █ - 1. ├─rlang:::F(NA %>% C()) - 2. ├─NA %>% C() - 3. └─rlang:::C(.) - 4. └─rlang:::f() - -Collapsed: - █ - 1. ├─[ rlang:::F(...) ] - 2. ├─[ NA %>% C() ] - 3. └─rlang:::C(.) - 4. └─rlang:::f() - -Branch: - 1. rlang:::F(NA %>% C()) - 3. rlang:::C(.) - 4. rlang:::f() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-children.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-children.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-children.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-children.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Full: - █ - 1. ├─NA %>% F() %>% G() %>% H() - 2. └─rlang:::H(.) - 3. └─rlang:::f() - 4. └─rlang:::h() - -Collapsed: - █ - 1. ├─[ NA %>% F() %>% G() %>% H() ] - 2. └─rlang:::H(.) - 3. └─rlang:::f() - 4. └─rlang:::h() - -Branch: - 1. NA %>% F() %>% G() %>% H() - 2. rlang:::H(.) - 3. rlang:::f() - 4. rlang:::h() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-complete1.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-complete1.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-complete1.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-complete1.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. ├─NA %>% T() - 2. └─rlang:::T(.) - -Collapsed: - █ - 1. ├─[ NA %>% T() ] - 2. └─rlang:::T(.) - -Branch: - 1. NA %>% T() - 2. rlang:::T(.) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-complete2.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-complete2.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-complete2.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-complete2.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. ├─NA %>% F() %>% T() - 2. └─rlang:::T(.) - -Collapsed: - █ - 1. ├─[ NA %>% F() %>% T() ] - 2. └─rlang:::T(.) - -Branch: - 1. NA %>% F() %>% T() - 2. rlang:::T(.) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-complete-leading1.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-complete-leading1.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-complete-leading1.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-complete-leading1.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. ├─F(NA) %>% T() - 2. └─rlang:::T(.) - -Collapsed: - █ - 1. ├─[ F(NA) %>% T() ] - 2. └─rlang:::T(.) - -Branch: - 1. F(NA) %>% T() - 2. rlang:::T(.) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-complete-leading2.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-complete-leading2.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-complete-leading2.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-complete-leading2.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. ├─F(NA) %>% F() %>% T() - 2. └─rlang:::T(.) - -Collapsed: - █ - 1. ├─[ F(NA) %>% F() %>% T() ] - 2. └─rlang:::T(.) - -Branch: - 1. F(NA) %>% F() %>% T() - 2. rlang:::T(.) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-incomplete-leading1.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-incomplete-leading1.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-incomplete-leading1.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-incomplete-leading1.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -Full: - █ - 1. ├─T(NA) %>% F() - 2. ├─rlang:::F(.) - 3. └─rlang:::T(NA) - -Collapsed: - █ - 1. ├─[ T(NA) %>% F() ] - 2. ├─[ rlang:::F(...) ] - 3. └─rlang:::T(NA) - -Branch: - 1. T(NA) %>% F() - 3. rlang:::T(NA) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-incomplete-leading2.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-incomplete-leading2.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-incomplete-leading2.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-incomplete-leading2.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -Full: - █ - 1. ├─F(NA) %>% F() %>% T() %>% F() %>% F() - 2. ├─rlang:::F(.) - 3. ├─rlang:::F(.) - 4. └─rlang:::T(.) - -Collapsed: - █ - 1. ├─[ F(NA) %>% F() %>% T() %>% F() %>% F() ] - 2. ├─[ rlang:::F(...) ] - 3. ├─[ rlang:::F(...) ] - 4. └─rlang:::T(.) - -Branch: - 1. F(NA) %>% F() %>% T() %>% F() %>% F() - 4. rlang:::T(.) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-incomplete.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-incomplete.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr-incomplete.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr-incomplete.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -Full: - █ - 1. ├─NA %>% F() %>% T() %>% F() %>% F() - 2. ├─rlang:::F(.) - 3. ├─rlang:::F(.) - 4. └─rlang:::T(.) - -Collapsed: - █ - 1. ├─[ NA %>% F() %>% T() %>% F() %>% F() ] - 2. ├─[ rlang:::F(...) ] - 3. ├─[ rlang:::F(...) ] - 4. └─rlang:::T(.) - -Branch: - 1. NA %>% F() %>% T() %>% F() %>% F() - 4. rlang:::T(.) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-collapse-magrittr.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-collapse-magrittr.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. ├─NULL %>% f() %>% g(1, 2) %>% h(3, ., 4) - 2. └─rlang:::h(3, ., 4) - -Collapsed: - █ - 1. ├─[ NULL %>% f() %>% g(1, 2) %>% h(3, ., 4) ] - 2. └─rlang:::h(3, ., 4) - -Branch: - 1. NULL %>% f() %>% g(1, 2) %>% h(3, ., 4) - 2. rlang:::h(3, ., 4) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-dangling-srcref.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-dangling-srcref.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-dangling-srcref.txt 2020-10-07 08:40:15.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-dangling-srcref.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. └─rlang:::f(current_env()) - 2. └─rlang:::g(e) - -Collapsed: - █ - 1. └─rlang:::f(current_env()) - 2. └─rlang:::g(e) - -Branch: - 1. rlang:::f(current_env()) - 2. rlang:::g(e) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-degenerate-null.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-degenerate-null.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-degenerate-null.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-degenerate-null.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -Full: - █ - 1. └─NULL - -Collapsed: - █ - 1. └─NULL - -Branch: - 1. NULL diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-degenerate-scalar.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-degenerate-scalar.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-degenerate-scalar.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-degenerate-scalar.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -Full: - █ - 1. └─1L - -Collapsed: - █ - 1. └─1L - -Branch: - 1. 1L diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-degenerate-sym.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-degenerate-sym.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-degenerate-sym.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-degenerate-sym.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -Full: - █ - 1. └─foo - -Collapsed: - █ - 1. └─foo - -Branch: - 1. foo diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-global-prefix.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-global-prefix.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-global-prefix.txt 2020-10-07 08:40:15.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-global-prefix.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. └─rlang:::g(current_env()) - 2. └─global::f(e) - -Collapsed: - █ - 1. └─rlang:::g(current_env()) - 2. └─global::f(e) - -Branch: - 1. rlang:::g(current_env()) - 2. global::f(e) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-local-prefix.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-local-prefix.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-local-prefix.txt 2020-10-07 08:40:15.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-local-prefix.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Full: - █ - 1. └─rlang:::g(current_env()) - 2. └─f(e) - -Collapsed: - █ - 1. └─rlang:::g(current_env()) - 2. └─f(e) - -Branch: - 1. rlang:::g(current_env()) - 2. f(e) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-non-collapsed-eval r-cran-rlang-0.4.10/tests/testthat/test-trace-non-collapsed-eval --- r-cran-rlang-0.4.8/tests/testthat/test-trace-non-collapsed-eval 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-non-collapsed-eval 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -Full: - █ - 1. ├─base::eval() - 2. └─base::.handleSimpleError(...) - 3. └─rlang:::h(simpleError(msg, call)) - -Collapsed: - █ - 1. ├─[ base::eval() ] - 2. └─base::.handleSimpleError(...) - 3. └─rlang:::h(simpleError(msg, call)) - -Branch: - 1. base::eval() - 2. base::.handleSimpleError(...) - 3. rlang:::h(simpleError(msg, call)) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-print.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-print.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-print.txt 2020-10-07 08:46:26.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-print.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ - █ - 1. └─rlang:::i() test-trace.R:30:2 - 2. └─rlang:::j(i) test-trace.R:23:7 - 3. └─rlang:::k(i) test-trace.R:24:21 - 4. └─rlang:::l(i) test-trace.R:27:4 - -█ diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace.R r-cran-rlang-0.4.10/tests/testthat/test-trace.R --- r-cran-rlang-0.4.8/tests/testthat/test-trace.R 2020-10-07 08:34:42.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,13 +1,9 @@ -context("trace.R") - local_options( rlang_trace_use_winch = FALSE ) # These tests must come first because print method includes srcrefs test_that("tree printing only changes deliberately", { - skip_unless_utf8() - # Because of srcrefs skip_on_cran() skip_if_not_installed("testthat", "2.99.0") @@ -29,7 +25,7 @@ l <- function(i) trace_back(e) trace <- i() - expect_known_output(file = test_path("test-trace-print.txt"), { + expect_snapshot({ print(trace, dir = dir) cat("\n") print(trace_subset(trace, 0L), dir = dir) @@ -37,8 +33,6 @@ }) test_that("can print tree with collapsed branches", { - skip_unless_utf8() - # Because of srcrefs skip_on_cran() skip_if_not_installed("testthat", "2.99.0") @@ -60,7 +54,7 @@ i <- function() { tryCatch(trace_back(e, bottom = 0)) } trace <- eval(quote(f())) - expect_known_trace_output(trace, + expect_snapshot_trace(trace, file = test_path("test-trace-collapsed1.txt"), dir = dir, srcrefs = TRUE @@ -72,7 +66,7 @@ h <- function() trace_back(e) trace <- eval(quote(f())) - expect_known_trace_output(trace, + expect_snapshot_trace(trace, file = test_path("test-trace-collapsed2.txt"), dir = dir, srcrefs = TRUE @@ -154,8 +148,6 @@ }) test_that("recursive frames are rewired to the global env", { - skip_unless_utf8() - dir <- normalizePath(test_path("..")) e <- environment() @@ -163,12 +155,10 @@ g <- function() trace_back(e) trace <- eval_tidy(quo(f())) - expect_known_trace_output(trace, file = "test-trace-recursive.txt") + expect_snapshot_trace(trace, file = "test-trace-recursive.txt") }) test_that("long backtrace branches are truncated", { - skip_unless_utf8() - e <- current_env() f <- function(n) { if (n) { @@ -178,7 +168,7 @@ } trace <- f(10) - expect_known_output(file = test_path("test-trace-truncate-backtrace-branch.txt"), { + expect_snapshot({ cat("Full:\n") print(trace, simplify = "branch", srcrefs = FALSE) cat("\n5 frames:\n") @@ -194,8 +184,6 @@ }) test_that("eval() frames are collapsed", { - skip_unless_utf8() - # Fake eval() call does not have same signature on old R skip_if(getRversion() < "3.4") @@ -204,17 +192,16 @@ g <- function() eval(quote(trace_back(e, bottom = 0))) trace <- f() - expect_known_trace_output(trace, file = "test-trace-collapse-eval.txt") + expect_snapshot_trace(trace, file = "test-trace-collapse-eval.txt") f <- function() base::evalq(g()) g <- function() evalq(trace_back(e, bottom = 0)) trace <- f() - expect_known_trace_output(trace, file = "test-trace-collapse-evalq.txt") + expect_snapshot_trace(trace, file = "test-trace-collapse-evalq.txt") }) test_that("%>% frames are collapsed", { - skip_unless_utf8() skip_if_not_installed("magrittr", "1.5.0.9000") skip_on_cran() @@ -229,17 +216,16 @@ h <- function(x, ...) trace_back(e) trace <- NULL %>% f() %>% g(1, 2) %>% h(3, ., 4) - expect_known_trace_output(trace, "test-trace-collapse-magrittr.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr.txt") trace <- f(NULL) %>% g(list(.)) %>% h(3, ., list(.)) - expect_known_trace_output(trace, "test-trace-collapse-magrittr2.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr2.txt") trace <- f(g(NULL %>% f()) %>% h()) - expect_known_trace_output(trace, "test-trace-collapse-magrittr3.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr3.txt") }) test_that("children of collapsed %>% frames have correct parent", { - skip_unless_utf8() skip_if_not_installed("magrittr", "1.5.0.9000") skip_on_cran() @@ -256,12 +242,10 @@ h <- function() trace_back(e) trace <- NA %>% F() %>% G() %>% H() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-children.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-children.txt") }) test_that("children of collapsed frames are rechained to correct parent", { - skip_unless_utf8() - # Fake eval() call does not have same signature on old R skip_if(getRversion() < "3.4") @@ -270,7 +254,7 @@ g <- function() trace_back(e) trace <- f() - expect_known_output(file = test_path("test-trace-collapse-children.txt"), { + expect_snapshot({ cat("Full:\n") print(trace, simplify = "none", srcrefs = FALSE) cat("\nCollapsed:\n") @@ -301,7 +285,6 @@ }) test_that("combinations of incomplete and leading pipes collapse properly", { - skip_unless_utf8() skip_if_not_installed("magrittr", "1.5.0.9000") skip_on_cran() @@ -315,29 +298,28 @@ T <- function(x) trace_back(e) trace <- NA %>% F() %>% T() %>% F() %>% F() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-incomplete.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-incomplete.txt") trace <- T(NA) %>% F() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-incomplete-leading1.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-incomplete-leading1.txt") trace <- F(NA) %>% F() %>% T() %>% F() %>% F() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-incomplete-leading2.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-incomplete-leading2.txt") trace <- NA %>% T() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-complete1.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-complete1.txt") trace <- NA %>% F() %>% T() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-complete2.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-complete2.txt") trace <- F(NA) %>% T() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-complete-leading1.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-complete-leading1.txt") trace <- F(NA) %>% F() %>% T() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-complete-leading2.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-complete-leading2.txt") }) test_that("calls before and after pipe are preserved", { - skip_unless_utf8() skip_if_not_installed("magrittr", "1.5.0.9000") skip_on_cran() @@ -353,18 +335,16 @@ f <- function() trace_back(e) trace <- F(NA %>% T()) - expect_known_trace_output(trace, "test-trace-collapse-magrittr-before-after1.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-before-after1.txt") trace <- NA %>% C() - expect_known_trace_output(trace, "test-trace-collapse-magrittr-before-after2.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-before-after2.txt") trace <- F(NA %>% C()) - expect_known_trace_output(trace, "test-trace-collapse-magrittr-before-after3.txt") + expect_snapshot_trace(trace, "test-trace-collapse-magrittr-before-after3.txt") }) test_that("always keep very first frame as part of backtrace branch", { - skip_unless_utf8() - # Fake eval() call does not have same signature on old R skip_if(getRversion() < "3.4") @@ -374,7 +354,7 @@ gen.default <- function(x) trace_back(e) trace <- gen() - expect_known_trace_output(trace, "test-trace-backtrace-branch-first-frame.txt") + expect_snapshot_trace(trace, "test-trace-backtrace-branch-first-frame.txt") }) test_that("can take the str() of a trace (#615)", { @@ -384,8 +364,6 @@ }) test_that("anonymous calls are stripped from backtraces", { - skip_unless_utf8() - e <- current_env() trace <- (function() { "foo" @@ -394,12 +372,10 @@ })() expect_identical(format(trace, simplify = "branch"), chr()) - expect_known_trace_output(trace, "test-trace-backtrace-anonymous.txt") + expect_snapshot_trace(trace, "test-trace-backtrace-anonymous.txt") }) test_that("collapsing of eval() frames detects when error occurs within eval()", { - skip_unless_utf8() - e <- NULL trace <- NULL @@ -416,26 +392,22 @@ error = calling(function(err) trace <<- trace_back(e)) )) - expect_known_trace_output(trace, "test-trace-non-collapsed-eval") + expect_snapshot_trace(trace, "test-trace-non-collapsed-eval") }) test_that("can print degenerate backtraces", { - skip_unless_utf8() - trace_sym <- new_trace(list(quote(foo)), int(0)) - expect_known_trace_output(trace_sym, file = "test-trace-degenerate-sym.txt") + expect_snapshot_trace(trace_sym, file = "test-trace-degenerate-sym.txt") trace_null <- new_trace(list(NULL), int(0)) - expect_known_trace_output(trace_null, file = "test-trace-degenerate-null.txt") + expect_snapshot_trace(trace_null, file = "test-trace-degenerate-null.txt") trace_scalar <- new_trace(list(1L), int(0)) - expect_known_trace_output(trace_scalar, file = "test-trace-degenerate-scalar.txt") + expect_snapshot_trace(trace_scalar, file = "test-trace-degenerate-scalar.txt") }) test_that("check for dangling promise in call CAR (#492)", { - skip_unless_utf8() - - expect_known_trace_output(file = "test-trace-call-car-promise.txt", local({ + expect_snapshot_trace(file = "test-trace-call-car-promise.txt", local({ e <- current_env() print.foo <- function(x) { @@ -448,8 +420,6 @@ }) test_that("dangling srcrefs are not printed", { - skip_unless_utf8() - from <- test_path("fixtures", "trace-srcref.R") to <- test_path("fixtures", "trace-srcref2.R") @@ -459,7 +429,7 @@ source(to, local = TRUE, keep.source = TRUE) unlink(to) - expect_known_trace_output( + expect_snapshot_trace( local(f(current_env())), file ="test-trace-dangling-srcref.txt", srcrefs = TRUE @@ -467,19 +437,15 @@ }) test_that("summary.rlang_trace() prints the full tree", { - skip_unless_utf8() - e <- current_env() f <- function() g() g <- function() h() h <- function() trace_back(e) trace <- f() - expect_known_output(summary(trace, srcrefs = FALSE), file = test_path("test-trace-summary.txt")) + expect_snapshot(summary(trace, srcrefs = FALSE)) }) test_that("unexported functions have `:::` prefix", { - skip_unless_utf8() - # Should be installed as part of the C API tests skip_if_not_installed("rlanglibtest") test_trace_unexported_child <- env_get(ns_env("rlanglibtest"), "test_trace_unexported_child") @@ -488,32 +454,26 @@ f <- function() test_trace_unexported_child(e) trace <- f() - expect_known_trace_output(trace, file = "test-trace-unexported-prefix.txt") + expect_snapshot_trace(trace, file = "test-trace-unexported-prefix.txt") }) test_that("global functions have `global::` prefix", { - skip_unless_utf8() - f <- eval_bare(expr(function(e) rlang::trace_back(e)), global_env()) g <- function(e) f(e) trace <- g(current_env()) - expect_known_trace_output(trace, file = "test-trace-global-prefix.txt") + expect_snapshot_trace(trace, file = "test-trace-global-prefix.txt") }) test_that("local functions inheriting from global do not have `global::` prefix", { - skip_unless_utf8() - f <- eval_bare(expr(function(e) rlang::trace_back(e)), env(global_env())) g <- function(e) f(e) trace <- g(current_env()) - expect_known_trace_output(trace, file = "test-trace-local-prefix.txt") + expect_snapshot_trace(trace, file = "test-trace-local-prefix.txt") }) test_that("can trim layers of backtraces", { - skip_unless_utf8() - e <- current_env() f <- function(n) identity(identity(g(n))) g <- function(n) identity(identity(h(n))) @@ -524,7 +484,7 @@ trace2 <- f(2) trace3 <- f(3) - expect_known_output(file = test_path("test-trace-trim.txt"), { + expect_snapshot({ local_options(rlang_trace_format_srcrefs = FALSE) cat_line("No trimming:") @@ -672,5 +632,5 @@ # FIXME: Weird trace structure trace <- f() - expect_is(trace, "rlang_trace") + expect_s3_class(trace, "rlang_trace") }) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-recursive.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-recursive.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-recursive.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-recursive.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -Full: - █ - 1. ├─rlang::eval_tidy(quo(f())) - 2. └─rlang:::f() - 3. └─rlang:::g() - -Collapsed: - █ - 1. ├─[ rlang::eval_tidy(...) ] - 2. └─rlang:::f() - 3. └─rlang:::g() - -Branch: - 1. rlang::eval_tidy(quo(f())) - 2. rlang:::f() - 3. rlang:::g() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-summary.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-summary.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-summary.txt 2020-10-07 08:40:15.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-summary.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ - █ - 1. └─rlang:::f() - 2. └─rlang:::g() - 3. └─rlang:::h() diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-trim.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-trim.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-trim.txt 2020-10-07 08:40:15.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-trim.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -No trimming: - █ - 1. └─rlang:::f(0) - 2. ├─base::identity(identity(g(n))) - 3. ├─base::identity(g(n)) - 4. └─rlang:::g(n) - 5. ├─base::identity(identity(h(n))) - 6. ├─base::identity(h(n)) - 7. └─rlang:::h(n) - 8. ├─base::identity(identity(trace_back(e, bottom = n))) - 9. ├─base::identity(trace_back(e, bottom = n)) - 10. └─rlang::trace_back(e, bottom = n) - - -One layer (the default): - █ - 1. └─rlang:::f(1) - 2. ├─base::identity(identity(g(n))) - 3. ├─base::identity(g(n)) - 4. └─rlang:::g(n) - 5. ├─base::identity(identity(h(n))) - 6. ├─base::identity(h(n)) - 7. └─rlang:::h(n) - - -Two layers: - █ - 1. └─rlang:::f(2) - 2. ├─base::identity(identity(g(n))) - 3. ├─base::identity(g(n)) - 4. └─rlang:::g(n) - - -Three layers: - █ - 1. └─rlang:::f(3) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-truncate-backtrace-branch.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-truncate-backtrace-branch.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-truncate-backtrace-branch.txt 2020-10-07 08:40:14.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-truncate-backtrace-branch.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -Full: - 1. rlang:::f(10) - 2. rlang:::f(n - 1) - 3. rlang:::f(n - 1) - 4. rlang:::f(n - 1) - 5. rlang:::f(n - 1) - 6. rlang:::f(n - 1) - 7. rlang:::f(n - 1) - 8. rlang:::f(n - 1) - 9. rlang:::f(n - 1) - 10. rlang:::f(n - 1) - 11. rlang:::f(n - 1) - -5 frames: - 1. rlang:::f(10) - 2. rlang:::f(n - 1) - 3. rlang:::f(n - 1) - ... - 10. rlang:::f(n - 1) - 11. rlang:::f(n - 1) - -2 frames: - 1. rlang:::f(10) - ... - 11. rlang:::f(n - 1) - -1 frame: - 1. rlang:::f(10) - ... diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-trace-unexported-prefix.txt r-cran-rlang-0.4.10/tests/testthat/test-trace-unexported-prefix.txt --- r-cran-rlang-0.4.8/tests/testthat/test-trace-unexported-prefix.txt 2020-10-07 08:40:15.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-trace-unexported-prefix.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -Full: - █ - 1. └─rlang:::f() - 2. └─rlanglibtest:::test_trace_unexported_child(e) - 3. └─rlanglibtest:::test_trace_unexported(e) - -Collapsed: - █ - 1. └─rlang:::f() - 2. └─rlanglibtest:::test_trace_unexported_child(e) - 3. └─rlanglibtest:::test_trace_unexported(e) - -Branch: - 1. rlang:::f() - 2. rlanglibtest:::test_trace_unexported_child(e) - 3. rlanglibtest:::test_trace_unexported(e) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-types.R r-cran-rlang-0.4.10/tests/testthat/test-types.R --- r-cran-rlang-0.4.8/tests/testthat/test-types.R 2019-06-24 14:49:22.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-types.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("types") - test_that("predicates match definitions", { expect_true(is_character(letters, 26)) expect_false(is_character(letters, 1)) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-typo-suggest.txt r-cran-rlang-0.4.10/tests/testthat/test-typo-suggest.txt --- r-cran-rlang-0.4.8/tests/testthat/test-typo-suggest.txt 2020-10-07 08:39:39.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-typo-suggest.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -> myarg <- "continuuos" -> arg_match0(myarg, c("discrete", "continuous")) -Error: `myarg` must be one of "discrete" or "continuous". -Did you mean "continuous"? - -> myarg <- "fou" -> arg_match0(myarg, c("bar", "foo")) -Error: `myarg` must be one of "bar" or "foo". -Did you mean "foo"? - -> myarg <- "fu" -> arg_match0(myarg, c("ba", "fo")) -Error: `myarg` must be one of "ba" or "fo". -Did you mean "fo"? - - -No suggestion when the edit distance is too large -================================================= - -> myarg <- "foobaz" -> arg_match0(myarg, c("fooquxs", "discrete")) -Error: `myarg` must be one of "fooquxs" or "discrete". - -> myarg <- "a" -> arg_match0(myarg, c("b", "c")) -Error: `myarg` must be one of "b" or "c". - - -Even with small possible typos, if there's a match it returns the match -======================================================================= - -> myarg <- "bas" -> arg_match0(myarg, c("foo", "baz", "bas")) -[1] "bas" - - -arg_nm is honored -================= - -> myarg <- "baq" -> arg_match0(myarg, c("foo", "baz", "bas"), arg_nm = "arg") -Error: `arg` must be one of "foo", "baz", or "bas". -Did you mean "baz"? - - -Corner case -=========== - -> arg_match0("", character()) -Error: `values` must have at least one element. - diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-utils.R r-cran-rlang-0.4.10/tests/testthat/test-utils.R --- r-cran-rlang-0.4.8/tests/testthat/test-utils.R 2020-01-23 16:24:42.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-utils.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("utils") - test_that("locale setters report old locale", { tryCatch( old <- suppressMessages(poke_mbcs_locale()), @@ -27,3 +25,9 @@ expect_identical(strip_trailing_newline("foo\n"), "foo") expect_identical(strip_trailing_newline("\n"), "") }) + +test_that("source_refs() creates source references", { + with_srcref("x <- quote({ NULL })") + attrib_names <- names(attributes(x)) + expect_true(all(c("srcref", "srcfile", "wholeSrcref") %in% attrib_names)) +}) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-vec-new.R r-cran-rlang-0.4.10/tests/testthat/test-vec-new.R --- r-cran-rlang-0.4.8/tests/testthat/test-vec-new.R 2020-06-22 09:02:20.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-vec-new.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("vec-new") - test_that("atomic vectors are spliced", { lgl <- lgl(TRUE, c(TRUE, FALSE), list(FALSE, FALSE)) expect_identical(lgl, c(TRUE, TRUE, FALSE, FALSE, FALSE)) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-vec.R r-cran-rlang-0.4.10/tests/testthat/test-vec.R --- r-cran-rlang-0.4.8/tests/testthat/test-vec.R 2018-12-17 14:37:51.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-vec.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("vec") - test_that("can poke a range to a vector", { y <- 11:15 x <- 1:5 diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-vec-squash.R r-cran-rlang-0.4.10/tests/testthat/test-vec-squash.R --- r-cran-rlang-0.4.8/tests/testthat/test-vec-squash.R 2020-01-17 17:20:49.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-vec-squash.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("vec-squash") - # Squashing ---------------------------------------------------------- test_that("vectors and names are squashed", { @@ -10,7 +8,7 @@ }) test_that("bad outer names warn even at depth", { - expect_warning(regex = "Outer names", + expect_warning(regexp = "Outer names", expect_identical(squash_dbl(list(list(list(A = c(a = 1))))), c(a = 1)) ) }) @@ -76,7 +74,7 @@ ptr <- rlang_test_is_spliceable[[1]] expect_identical(flatten_if(x, ptr), list(obj[[1]], splice(obj), unclass(obj))) - expect_is(rlang_test_is_spliceable, "fn_pointer") + expect_s3_class(rlang_test_is_spliceable, "fn_pointer") }) test_that("flatten() splices names", { diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-vec-utils.R r-cran-rlang-0.4.10/tests/testthat/test-vec-utils.R --- r-cran-rlang-0.4.8/tests/testthat/test-vec-utils.R 2019-06-11 14:01:54.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-vec-utils.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("vec-utils") - test_that("seq2() creates increasing sequences", { expect_identical(seq2(2, 3), 2:3) expect_identical(seq2(3, 2), int()) diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-weakref.R r-cran-rlang-0.4.10/tests/testthat/test-weakref.R --- r-cran-rlang-0.4.8/tests/testthat/test-weakref.R 2019-06-13 20:33:43.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-weakref.R 2020-12-18 09:00:51.000000000 +0000 @@ -1,5 +1,3 @@ -context("weakref") - test_that("weakref with key and no value allows key to be GC'd", { # This is the case when a weakref is used like a weak pointer (with no # value). diff -Nru r-cran-rlang-0.4.8/tests/testthat/test-with-abort.txt r-cran-rlang-0.4.10/tests/testthat/test-with-abort.txt --- r-cran-rlang-0.4.8/tests/testthat/test-with-abort.txt 2020-10-07 08:39:52.000000000 +0000 +++ r-cran-rlang-0.4.10/tests/testthat/test-with-abort.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -print(): - -█ -├─ -│ High-level message -└─ - Low-level message -Backtrace: - 1. base::identity(catch_cnd(a())) - 9. rlang:::a() - 10. rlang:::b() - 11. rlang:::c() - 18. rlang:::f() - 19. rlang:::g() - 20. rlang:::h() - - -summary(): - -█ -├─ -│ High-level message -└─ - Low-level message -Backtrace: - █ - 1. ├─base::identity(catch_cnd(a())) - 2. ├─rlang::catch_cnd(a()) - 3. │ ├─rlang::eval_bare(...) - 4. │ ├─base::tryCatch(...) - 5. │ │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 6. │ │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 7. │ │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 8. │ └─base::force(expr) - 9. └─rlang:::a() - 10. └─rlang:::b() - 11. └─rlang:::c() - 12. ├─base::tryCatch(...) - 13. │ └─base:::tryCatchList(expr, classes, parentenv, handlers) - 14. │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]]) - 15. │ └─base:::doTryCatch(return(expr), name, parentenv, handler) - 16. ├─rlang::with_abort(f()) - 17. │ └─base::withCallingHandlers(...) - 18. └─rlang:::f() - 19. └─rlang:::g() - 20. └─rlang:::h()